/////////////////////////////////////////////////////////////////////////////// // Filename: IOCPServerCtrl.cpp // Coder : °­µ¿¸í (Edithe@chollian.net) // Comp. : Navezine // Compiler: Visual C++ .net // Title : IOCP Base ÄÁÆ®·Ñ·¯ Ŭ·¡½º /////////////////////////////////////////////////////////////////////////////// #include "Global.h" #include "NFServerCtrl.h" #include #include namespace NaveServer { // INT iMaxRecvPacket = 0; // INT iRecvPacket = 0; // ÀÌ °´Ã¼°¡ Ŭ¶óÀÌ¾ðÆ®¿Í ¿¬°á °Ë»ç // DWORD uRecvTickCnt = 0; // ¼ö½Å Tick Count ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// NFServerCtrl::NFServerCtrl() { m_bServerRun = FALSE; // ¼­¹ö ±¸µ¿»óÅ m_bPause = FALSE; m_nMaxThreadNum = (GetNumberOfProcess() * 2); // CPU¼ö * 2°³·Î Thread ¼ö °áÁ¤ m_iPort = 0; m_iMaxConn = 50; m_pWorkThread = NULL; // ¸ÞÀÎ ½º·¹µå ÇÚµé m_hProcThread = 0; m_hPacketThread = 0; m_hIOCP = NULL; // IOCP ÇÚµé m_pUpdateManager = new NFUpdateManager(); } NFServerCtrl::~NFServerCtrl() { m_bServerRun = FALSE; _DELETE(m_pUpdateManager); } ////////////////////////////////////////////////////////////////// // [1]DESCRIPTION : IOCP ÇÚµé »ý¼º // // [2]PARAMETER : void // // [3]RETURN : HANDLE = »ý¼ºµÈ IOCP // // [4]DATE : 2003³â 10¿ù 24ÀÏ // ////////////////////////////////////////////////////////////////// HANDLE NFServerCtrl::CreateIOCP() { return CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0); } ////////////////////////////////////////////////////////////////// // [1]DESCRIPTION : Listen ¼ÒÄÏ »ý¼º // // [2]PARAMETER : void // // [3]RETURN : SOCKET = »ý¼ºµÈ LISTEN SOCKET // // [4]DATE : 2003³â 10¿ù 24ÀÏ // ////////////////////////////////////////////////////////////////// SOCKET NFServerCtrl::CreateListenSocket(INT nServerPort, CHAR cBindQue) { SOCKET Socket = NULL; // a Socket Variable for using Listener // ¼ÒÄÏ »óÅ ¼³Á¤ ±¸Á¶Ã¼ ¼±¾ð SOCKADDR_IN addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons( (short)nServerPort ); // [1] Create Listen Socket Socket = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED ); if(Socket == NULL) return Socket; // [2] bind listen socket if(bind(Socket,(SOCKADDR *)&addr,sizeof(addr)) != 0) return Socket; // [3] listening for an concurrent incoming connections limited in 5 listen(Socket, cBindQue); LISTENER stLin; stLin.Init(); stLin.s = Socket; stLin.nPort = nServerPort; stLin.cBindQue = cBindQue; m_vecListener.push_back(stLin); return Socket; } ////////////////////////////////////////////////////////////////// // [1]DESCRIPTION : Listen Socket À» iocp ¼ÒÄÏ¿¡ ¿¬°á // // [2]PARAMETER : SOCKET sckListener // // [3]RETURN : HANDLE = ¿¬°áµÈ IOCP // // [4]DATE : 2003³â 10¿ù 24ÀÏ // ////////////////////////////////////////////////////////////////// HANDLE NFServerCtrl::ConnectIOCPSocket(SOCKET sckListener) { return CreateIoCompletionPort((HANDLE)sckListener,m_hIOCP,0,0); } ////////////////////////////////////////////////////////////////// // [1]DESCRIPTION : SOCKET°ú·Ã ¶óÀ̺귯¸® Ȱ¼ºÈ­ // // [2]PARAMETER : void // // [3]RETURN : void // // [4]DATE : 2003³â 10¿ù 24ÀÏ // ////////////////////////////////////////////////////////////////// BOOL NFServerCtrl::InitSocket() { WSADATA wsaData; // Initialzing Variables return (SOCKET_ERROR != WSAStartup(0x202,&wsaData)); // Start Up } ////////////////////////////////////////////////////////////////// // [1]DESCRIPTION : ½Ã½ºÅÛÀÇ CPU ¼ö¸¦ ±¸ÇÔ // // [2]PARAMETER : void // // [3]RETURN : INT = ÇöÀç ½Ã½ºÅÛÀÇ CPU ¼ö ¹Ýȯ // // [4]DATE : 2003³â 10¿ù 24ÀÏ // ////////////////////////////////////////////////////////////////// INT NFServerCtrl::GetNumberOfProcess() { SYSTEM_INFO si; // a System Info Structure Object GetSystemInfo( &si ); // Get the System Information return (INT)si.dwNumberOfProcessors; // return the number of processors } ////////////////////////////////////////////////////////////////// // [1]DESCRIPTION : ¼­¹ö Á¤Áö // // [2]PARAMETER : void // // [3]RETURN : BOOL - ÀÇ¹Ì ¾øÀ½ // // [4]DATE : 2003³â 10¿ù 24ÀÏ // ////////////////////////////////////////////////////////////////// BOOL NFServerCtrl::Stop() { ////////////////////////////////////////////////////////////////////// // Server Closing Process // ////////////////////////////////////////////////////////////////////// INT nCnt; // [01] Queue Suicide Packets into each IOCP Main Thread for( nCnt = 0; nCnt < m_nMaxThreadNum; nCnt++ ) { if(PostQueuedCompletionStatus(m_hIOCP,0,IOCP_SHUTDOWN,0) ==NULL) return FALSE; } // [02] Wait for thread terminations nCnt = WaitForMultipleObjects( m_nMaxThreadNum, m_pWorkThread, TRUE, 15000 ); switch ( nCnt ) { case WAIT_TIMEOUT: LOG_ERROR((L"Not All WorkThreads Died in Time.")); break; case WAIT_FAILED: LOG_ERROR((L"WAIT_FAILED, WaitForMultipleObjects().")); break; default: break; } // [03] Close Thread Handles if( m_pWorkThread ) { for( nCnt = 0; nCnt < m_nMaxThreadNum; nCnt++ ) CloseHandle( m_pWorkThread[nCnt] ); _DELETE_ARRAY(m_pWorkThread); } // [04] Process Thread Stop and Close m_bServerRun = FALSE; CloseHandle(m_hProcThread); CloseHandle(m_hPacketThread); if(ReleaseSession() == TRUE) { LOG_IMPORTANT((L"shutdown session..")); } // [05] Close Listener Socket int iListener = m_vecListener.size(); for(int i = 0; i < iListener; ++i) { m_vecListener[i].Release(); } // [6] Close IOCP Handle if(m_hIOCP) CloseHandle(m_hIOCP); // [7] ¼ÒÄÏ ¶óÀ̺귯¸® Á¾·á WSACleanup(); // [8] Show the Result of Close Processing LOG_IMPORTANT((L"shutdown sequence finished..")); return TRUE; } ////////////////////////////////////////////////////////////////// // [1]DESCRIPTION : ¼­¹ö ±¸µ¿ // // [2]PARAMETER : void // // [3]RETURN : BOOL - ÀÇ¹Ì ¾øÀ½ // // [4]DATE : 2003³â 10¿ù 24ÀÏ // ////////////////////////////////////////////////////////////////// BOOL NFServerCtrl::Start(INT nPort, INT nMaxConn, INT nMaxThreadNum) { m_iPort = nPort; m_iMaxConn = nMaxConn; // ÇöÀç »ç¿ëµÇ´Â ½º·¹µå´Â Work¿ë ½º·¹µå CPU*2°³ // ¹ÞÀº ÆÐŶÀ̳ª À̺¥Æ®µîÀ» ó¸®ÇÏ´Â Update¿ë ½º·¹µå 1°³¸¦ »ç¿ëÇÑ´Ù. // ¸¸¾à ¸ó½ºÅͳª ±âŸ ´Ù¸¥ °ÔÀÓÀÇ »óŸ¦ ¾÷µ¥ÀÌÆ® ÇϱâÀ§Çؼ­´Â // Á÷Á¢ ÀÛ¾÷¿ë ½º·¹µå¸¦ »ý¼ºÇØ ¹°¸®¸é µÈ´Ù. /* »ý°¢ÇÏ´Â°Í IOCP¿ë ½º·¹µå CPU°³¼ö¸¸Å­ (IOCP¸¦ ÅëÇØ Accept, Recv, Send¸¦ Çϱâ À§ÇÑ ½º·¹µå) EventUpdate¿ë ½º·¹µå 1°³ (ÆÐŶÀ» ¾÷µ¥ÀÌÆ® Çϱâ À§ÇÑ Å¥) °ÔÀÓÀÇ »óÅÂ(¸ó½ºÅ͹ױ⟻óÅÂ)¿ë ½º·¹µå ?°³ */ // 0ÀÌ¾Æ´Ï¸é ±× °³¼ö »ç¿ë if(nMaxThreadNum != 0) m_nMaxThreadNum = nMaxThreadNum; else m_nMaxThreadNum = (GetNumberOfProcess() * 2); // CPU¼ö * 2°³·Î Thread ¼ö °áÁ¤ // [00] º¯¼ö ¹× °´Ã¼ ¼±¾ð INT nCnt = 0; // ·çÇÁ º¯¼ö UINT nDummy; // ¾²·¹±â °ª ó¸® SOCKET skListener; // [01] initialize socket library if(!InitSocket()) goto Error_Procss; // [02] Create IOCP if((m_hIOCP = CreateIOCP()) == NULL) goto Error_Procss; // [03] Create Listener Socket if((skListener = CreateListenSocket(m_iPort)) == INVALID_SOCKET) goto Error_Procss; // [04] Connect listener socket to IOCP if(ConnectIOCPSocket(skListener) == NULL) goto Error_Procss; // [05] È­¸é¿¡ ¼­¹ö Á¤º¸ Ç¥½Ã ShowServerInfo(); // [06] Create Session.. if(CreateSession(skListener) == FALSE) goto Error_Procss; // [07] Update Session.. if((m_pWorkThread = new HANDLE[m_nMaxThreadNum]) == NULL) goto Error_Procss; // Create thread Control Handle for(nCnt = 0; nCnt < m_nMaxThreadNum; nCnt++) // Run Thread { if((m_pWorkThread[nCnt] = (HANDLE)_beginthreadex(0,0,Thread_MainEx,m_hIOCP,0,&nDummy)) == NULL) goto Error_Procss; } //--------------> Server Initializing has been done <---------------// // [8] Process Thread »ý¼ºÇϱâ m_bServerRun = TRUE; if((m_hProcThread = (HANDLE)_beginthreadex(0,0,Process_MainEx,this,0,&nDummy)) == NULL) goto Error_Procss; // [9] Process Thread »ý¼ºÇϱâ if((m_hPacketThread = (HANDLE)_beginthreadex(0,0,Packet_MainEx,this,0,&nDummy)) == NULL) goto Error_Procss; return TRUE; Error_Procss: Stop(); m_bServerRun = FALSE; return FALSE; } VOID NFServerCtrl::ShowServerInfo() { WCHAR szDate[32], szTime[32]; _tzset(); _wstrdate( szDate ); _wstrtime( szTime ); LOG_IMPORTANT((L"------------------------------------------------")); LOG_IMPORTANT((L" %s initialized at %s, %s", L"Server", szDate, szTime) ); LOG_IMPORTANT((L"------------------------------------------------")); ////////////////////////////////////////////////////////////////////// // Server start // ////////////////////////////////////////////////////////////////////// LOG_IMPORTANT((L"------------------------------------------------")); LOG_IMPORTANT((L"| SERVER START |")); LOG_IMPORTANT((L"------------------------------------------------")); WCHAR Ip[32]; GetLocalIP(Ip); LOG_IMPORTANT((L"IP(%s) Port(%d)", Ip, m_iPort )); } VOID NFServerCtrl::Pause(BOOL bPause) { m_bPause = bPause; } VOID NFServerCtrl::Update() { /* if(timeGetTime() - uRecvTickCnt > 1000) { InterlockedExchange((LONG*)&iMaxRecvPacket,iRecvPacket); InterlockedExchange((LONG*)&iRecvPacket,0); InterlockedExchange((LONG*)&uRecvTickCnt,timeGetTime()); } */ } ////////////////////////////////////////////////////////////////// // [1]DESCRIPTION : IOCP󸮸¦ ´ã´çÇÏ´Â ¸ÞÀÎ ½º·¹µå // // [2]PARAMETER : lpVoid - IOCP Handle // // [3]RETURN : BOOL - ÀÇ¹Ì ¾øÀ½ // // [4]DATE : 2003³â 10¿ù 24ÀÏ // ////////////////////////////////////////////////////////////////// unsigned NFServerCtrl::Thread_MainEx(LPVOID lpVoid) { DWORD dwIoSize; // ¿Ï·áó¸® »çÀÌÁî ¾òÀ½ ULONG lCompletionKey; // ¹«ÇÑ ·çÇÁ Å»Ãâ ¿ëÀÌ µÊ BOOL bSuccess; // ºí·°Å· ó¸® ¿¡·¯ È®ÀÎ HANDLE hIOCP = (HANDLE)lpVoid; // IOCP ÇÚµé ¾òÀ½ LPOVERLAPPED lpOverlapped; // Áßø È®Àå Æ÷ÀÎÅÍ //////////// // ¹«ÇÑ ·çÇÁ while( TRUE ) { // IOCP 󸮸¦ ±â´Ù¸®´Â BLOCKING MODE bSuccess = GetQueuedCompletionStatus(hIOCP, // IOCP Handle &dwIoSize, // ó¸® »çÀÌÁî &lCompletionKey, // ¿Ï·á Ű (LPOVERLAPPED*) &lpOverlapped, // Áßø È®Àå INFINITE); // Waiting Time LPOVERLAPPEDPLUS lpOverlapPlus = (LPOVERLAPPEDPLUS)lpOverlapped; if(bSuccess) { // Á¾·á ½ÅÈ£°¡ µé¾î¿Ô´Ù¸é, ·çÇÁ Å»Ãâ if( lCompletionKey == IOCP_SHUTDOWN ) break; if( NULL != lpOverlapPlus ) { /////////////////////////////////////////////// // 󸮰¡ Á¤»óÀûÀ¸·Î ÀÌ·ç¾îÁø´Ù¸é ÀÌÂÊÀ¸·Î... lpOverlapPlus->dwBytes = dwIoSize; // ó¸® µ¥ÀÌŸ Size // ó¸® º¯¼ö Cast º¯È¯ // ¼Óµµ¸¦ À§ÇØ ¸ÞÀÎÇÁ·¹ÀÓ¿¡¼± try~catch¸¦ »«´Ù. // ¾Ë¼ö ¾ø´Â ¿À·ù¸¦ °Ë»çÇϱâ À§Çؼ± Exception::EnableUnhandledExceptioinFilter(true)¸¦ »ç¿ëÇÑ´Ù /* // Recv Ä«¿îÆ® ó¸® if(lpOverlapPlus->nConnState == ClientIoRead) { InterlockedExchange((LONG*)&iRecvPacket,iRecvPacket+1); } */ NFConnection* lpClientConn = (NFConnection*) lpOverlapPlus->pClientConn; lpClientConn->DoIo(lpOverlapPlus); // IOCP ó¸® Çڵ鸵 } } else { if(!lpOverlapPlus) { LOG_ERROR((L"Critical Error on GetQueuedCompletionStatus().")); } else { // ó¸® º¯¼ö Cast º¯È¯ NFConnection* lpClientConn = (NFConnection*) lpOverlapPlus->pClientConn; // °­Á¦·Î ClearÇØÁÖ¸é ¾ÈµÈ´Ù. (µ¥ÀÌŸ°¡ Á¦´ë·Î ÃʱâÈ­ µÇÁö ¾ÊÀ»¼öµµ ÀÖ´Ù) // lpClientConn->Clear(); // LOG_ERROR(("[%04d] IOCP OverlapPlus Error, Close_Open()È£Ãâ. SOCKET_ERROR, %d", lpClientConn->GetIndex(), WSAGetLastError())); lpClientConn->SetClose_Open(lpOverlapPlus, TRUE); // ¿¬°á ÇØÁ¦ } } } return 0; } ////////////////////////////////////////////////////////////////// // [1]DESCRIPTION : IOCP󸮸¦ ´ã´çÇÏ´Â ¸ÞÀÎ ½º·¹µå // // [2]PARAMETER : lpVoid - IOCP Handle // // [3]RETURN : BOOL - ÀÇ¹Ì ¾øÀ½ // // [4]DATE : 2003³â 10¿ù 24ÀÏ // ////////////////////////////////////////////////////////////////// unsigned NFServerCtrl::Process_MainEx(LPVOID lpVoid) { NFServerCtrl* pCtrl = (NFServerCtrl*)lpVoid; // IOCP ÇÚµé ¾òÀ½ assert(pCtrl); while( pCtrl->IsRun()) { if(pCtrl->IsPause()) { Sleep(1); continue; } pCtrl->Update(); Sleep(1); } return 0; } ////////////////////////////////////////////////////////////////// // [1]DESCRIPTION : UpateQue󸮸¦ ´ã´çÇÏ´Â ¸ÞÀÎ ½º·¹µå // // [2]PARAMETER : lpVoid - IOCP Handle // // [3]RETURN : BOOL - ÀÇ¹Ì ¾øÀ½ // // [4]DATE : 2003³â 10¿ù 24ÀÏ // ////////////////////////////////////////////////////////////////// unsigned NFServerCtrl::Packet_MainEx(LPVOID lpVoid) { NFServerCtrl* pCtrl = (NFServerCtrl*)lpVoid; // IOCP ÇÚµé ¾òÀ½ NFUpdateManager* pUpdateManager = NFUpdateManager::GetInstancePtr(); assert(pCtrl); assert(pUpdateManager); while( pCtrl->IsRun()) { pUpdateManager->Update(); Sleep(1); } return 0; } }