#include "stdafx.h" #include #include #include "IOCPServer.h" #include "IoHandler.h" #include "SessionList.h" #include "Session.h" #include "SendBuffer.h" #include "RecvBuffer.h" typedef std::map, module::RedirectedAllocator > IOHANDLER_MAP; //================================================================================================== /** @remarks InPimpl ¸É¹ö ¼±¾ð */ //================================================================================================== struct IOCPServer::InPimpl { HANDLE send_thread_handle_; bool shutdown_; IOHANDLER_MAP io_handler_table_; }; //================================================================================================== /** @remarks ¼¼¼Ç ¸®½ºÆ®¸¦ ¼øÈ¸ÇÏ¸ç º¸³»±â ¹öÆÛ¿¡ ÀÖ´Â ÆÐŶµéÀ» Àü¼ÛÇÏ´Â ¾²·¹µå @param param IOCP ¼­¹öÀÇ Æ÷ÀÎÅÍ */ //================================================================================================== unsigned __stdcall send_thread(LPVOID param) { IOCPServer* const iocp_server = reinterpret_cast(param); IOCPServer::InPimpl* const iocp_impl = iocp_server->in_impl_; while (iocp_impl->shutdown_ == false) { Sleep(1); // for context-switching, no busy-waiting IOHANDLER_MAP::const_iterator it = iocp_impl->io_handler_table_.begin(); const IOHANDLER_MAP::const_iterator end = iocp_impl->io_handler_table_.end(); for (; it != end; ++it) { IoHandler* const io_handler = it->second; io_handler->ProcessSend(); } } return 0; } //================================================================================================== //================================================================================================== //================================================================================================== IOCPServer::IOCPServer() : in_impl_(new InPimpl) { in_impl_->shutdown_ = false; in_impl_->send_thread_handle_ = NULL; } IOCPServer::~IOCPServer() { if (!in_impl_->shutdown_) { Shutdown(); } if (in_impl_->send_thread_handle_) { CloseHandle(in_impl_->send_thread_handle_); } delete in_impl_; in_impl_ = NULL; WSACleanup(); } //================================================================================================== /** @remarks ¼­¹ö¸¦ ÃʱâÈ­ÇÑ´Ù. @param description ¼­¹ö ÃʱâÈ­¿¡ ÇÊ¿äÇÑ Á¤º¸¸¦ ´ãÀº ±¸Á¶Ã¼ÀÇ Æ÷ÀÎÅÍ @retval BOOL À©¼Ó ÃʱâÈ­¿¡ ½ÇÆÐÇϰųª ¸®½¼ ¼ÒÄÏ »ý¼º¿¡ ½ÇÆÐÇϸé false¸¦ ¸®ÅÏÇÑ´Ù. */ //================================================================================================== BOOL IOCPServer::Init(LPIOHANDLER_DESC description, DWORD number_of_io_handlers) { // À©¼Ó ÃʱâÈ­ if (!InitWinsock()) { return false; } for (DWORD i = 0; i < number_of_io_handlers; ++i) { CreateIoHandler(description + i); } // Send ¿öÄ¿ ¾²·¹µå »ý¼º unsigned int thread_id; in_impl_->send_thread_handle_ = \ (HANDLE)_beginthreadex(NULL, 0, &send_thread, (LPVOID)this, 0, &thread_id); return true; } void IOCPServer::CreateIoHandler(LPIOHANDLER_DESC description) { IoHandler* const io_handler = new IoHandler; ; io_handler->Init(this, description); in_impl_->io_handler_table_.insert(std::make_pair(io_handler->GetKey(), io_handler)); } ///--------------------------------------------------------------------------- ///--------------------------------------------------------------------------- // ´ã´ö Ãß°¡. ÇöÀç ÆÐŶ¹öÆÛ »óŸ¦ ¾Ë±âÀ§Çؼ­ Ãß°¡! ///--------------------------------------------------------------------------- ///--------------------------------------------------------------------------- DWORD IOCPServer::GetMaxBuffer(DWORD io_handler_key, DWORD session_index, BOOL is_send_buffer, BOOL is_select_max_buffer) { IoHandler* const io_handler = GetIoHandler(io_handler_key); if (io_handler == NULL) { return 0; } // Session* const session = io_handler->GetSession(session_index); if (session == NULL) { return 0; } // DWORD max_buffer_size = 0; DWORD current_used_size = 0; if (is_send_buffer) { const SendBuffer* send_buffer = session->GetSendBuffer(); // lockless check send_buffer->GetBufferSizeInfo(max_buffer_size, current_used_size); } else { const RecvBuffer* recv_buffer = session->GetRecvBuffer(); // lockless check recv_buffer->GetBufferSizeInfo(max_buffer_size, current_used_size); } return is_select_max_buffer ? max_buffer_size : current_used_size; } void IOCPServer::Display(DWORD io_handler_key, DWORD over_boundary_length) { IoHandler* const io_handler = GetIoHandler(io_handler_key); if (io_handler == NULL) { return; } SessionList* const active_sessions = io_handler->GetActiveSessionList(); SESSION_LIST::const_iterator it = active_sessions->begin(); const SESSION_LIST::const_iterator end = active_sessions->end(); DWORD max_buffer_size = 0; DWORD current_used_size = 0; for ( ; it != end; ++it) { Session* session = *it; const SendBuffer* send_buffer = session->GetSendBuffer(); // lockless check send_buffer->GetBufferSizeInfo(max_buffer_size, current_used_size); if (current_used_size >= over_boundary_length) { session->OnLogString("Session[%d] SendBuffer Size[%d]", session->GetIndex(), current_used_size); } const RecvBuffer* recv_buffer = session->GetRecvBuffer(); // lockless check recv_buffer->GetBufferSizeInfo(max_buffer_size, current_used_size); if (current_used_size >= over_boundary_length) { session->OnLogString("Session[%d] RecvBuffer Size[%d]", session->GetIndex(), current_used_size); } } } IoHandler* IOCPServer::GetIoHandler(DWORD io_handler_key) { const IOHANDLER_MAP& io_handler_table = in_impl_->io_handler_table_; IOHANDLER_MAP::const_iterator found = io_handler_table.find(io_handler_key); if (found != io_handler_table.end()) { IoHandler* io_handler = found->second; return io_handler; } return NULL; } void IOCPServer::Shutdown() { in_impl_->shutdown_ = true; // Send ¿öÄ¿ ¾²·¹µå°¡ Á¾·áµÉ ¶§±îÁö ±â´Ù¸°´Ù. WaitForSingleObject(in_impl_->send_thread_handle_, INFINITE); // IoHandlerµéÀ» Á¾·á½ÃŰ°í Æ÷ÀÎÅ͸¦ »èÁ¦ÇÑ´Ù. IOHANDLER_MAP::const_iterator it = in_impl_->io_handler_table_.begin(); const IOHANDLER_MAP::const_iterator end = in_impl_->io_handler_table_.end(); for (; it != end; ++it) { IoHandler* io_handler = it->second; ; io_handler->Shutdown(); delete io_handler; } in_impl_->io_handler_table_.clear(); } //================================================================================================== /** @remarks AcceptµÈ ¼¼¼Ç°ú ConnectµÈ ¼¼¼ÇµéÀ» IOCP¿¡ µî·ÏÇϸ鼭 Ȱ¼º ¸®½ºÆ®·Î ¿Å±â°í ¸ðµç ¼¼¼ÇÀÇ ¹Þ±â ¹öÆÛ¸¦ °Ë»çÇÏ¿© ÆÐŶÀ» ó¸®ÇÏ´Â µîÀÇ ÀÛ¾÷À» ÇÑ´Ù. */ //================================================================================================== void IOCPServer::Update() { IOHANDLER_MAP::const_iterator it = in_impl_->io_handler_table_.begin(); const IOHANDLER_MAP::const_iterator end = in_impl_->io_handler_table_.end(); for (; it != end; ++it) { IoHandler* io_handler = it->second; ; io_handler->Update(); } } BOOL IOCPServer::StartListen(DWORD io_handler_key, char* ip_string, WORD port) { IOHANDLER_MAP::const_iterator found = in_impl_->io_handler_table_.find(io_handler_key); const bool must_be_find_io_handler = (found != in_impl_->io_handler_table_.end()); assert(must_be_find_io_handler); if (must_be_find_io_handler == false) { return false; } IoHandler* io_handler = found->second; return io_handler->StartListen(ip_string, port); } //================================================================================================== /** @remarks - connect ¾²·¹µå¸¦ »ç¿ëÇÏ¿© Á¢¼ÓÀ» ½ÃµµÇÑ´Ù. @param io_handler_key - Á¢¼ÓÀ» ½ÃµµÇϱâ À§ÇÑ ¼¼¼ÇÀ» °¡Áö°í ÀÖ´Â I/O Çڵ鷯ÀÇ Å° - Á¢¼Ó ¼º°ø ¶Ç´Â ½ÇÆÐ½Ã OnConnect(BOOL)ÀÌ È£ÃâµÈ´Ù. @param szIP Á¢¼ÓÇÒ IP @param port Á¢¼ÓÇÒ Æ÷Æ® @retval DWORD Á¢¼ÓÀ» ½ÃµµÇÒ ¼¼¼ÇÀÇ À妽º */ //================================================================================================== DWORD IOCPServer::Connect(DWORD io_handler_key, NetworkObject* network_object, char* ip_string, WORD port) { if (network_object == NULL) { return 0; } IOHANDLER_MAP::const_iterator found = in_impl_->io_handler_table_.find(io_handler_key); const bool must_be_find_io_handler = (found != in_impl_->io_handler_table_.end()); assert(must_be_find_io_handler); if (must_be_find_io_handler == false) { return 0; } IoHandler* io_handler = found->second; return io_handler->Connect(network_object, ip_string, port); } BOOL IOCPServer::IsListening(DWORD io_handler_key) { IOHANDLER_MAP::const_iterator found = in_impl_->io_handler_table_.find(io_handler_key); const bool must_be_find_io_handler = (found != in_impl_->io_handler_table_.end()); assert(must_be_find_io_handler); if (must_be_find_io_handler == false) { return false; } IoHandler* io_handler = found->second; return io_handler->IsListening(); } void IOCPServer::SuspendListenThread(DWORD io_handler_key) { IOHANDLER_MAP::const_iterator found = in_impl_->io_handler_table_.find(io_handler_key); const bool must_be_find_io_handler = (found != in_impl_->io_handler_table_.end()); assert(must_be_find_io_handler); if (must_be_find_io_handler == false) { return; } IoHandler* io_handler = found->second; io_handler->SuspendListenThread(); } void IOCPServer::ResumeListenThread(DWORD io_handler_key) { IOHANDLER_MAP::const_iterator found = in_impl_->io_handler_table_.find(io_handler_key); const bool must_be_find_io_handler = (found != in_impl_->io_handler_table_.end()); assert(must_be_find_io_handler); if (must_be_find_io_handler == false) { return; } IoHandler* io_handler = found->second; io_handler->ResumeListenThread(); } DWORD IOCPServer::GetNumberOfConnections(DWORD io_handler_key) { IOHANDLER_MAP::const_iterator found = in_impl_->io_handler_table_.find(io_handler_key); const bool must_be_find_io_handler = (found != in_impl_->io_handler_table_.end()); assert(must_be_find_io_handler); if (must_be_find_io_handler == false) { return 0; } IoHandler* io_handler = found->second; return io_handler->GetNumberOfConnections(); } //================================================================================================== /** @remarks À©¼ÓÀ» ÃʱâÈ­ÇÑ´Ù. */ //================================================================================================== BOOL IOCPServer::InitWinsock() { WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); if (wsaData.wVersion != MAKEWORD(2, 2)) { WSACleanup(); return false; } return true; }