#include "StdAfx.h" #include "IOCPController.h" BOOL CIOCPController::m_bIsStartUp = FALSE; CIOCPController::CIOCPController(void) { InitializeCriticalSection(&m_csContext); // µ¿±âÈ­ º¯¼ö Ãß°¡ m_nExit = FALSE; m_pPerSocketCtxMemPool = NULL; m_pRecvMemPool = NULL; m_pSendMemPool = NULL; ZeroMemory(m_strFileName, MAX_PATH); m_nLogYear = 0; m_nLogMonth = 0; m_nLogDay = 0; m_nPort = 0; m_strIP = _T(""); m_pSocketCtx = NULL; m_bReconnect = FALSE; m_bConnected = FALSE; m_hMutexLog = CreateMutex(NULL, FALSE, _T("Mutex_IOCPLog")); m_EventExitConnectThread = NULL; for(int i=0; i<10; i++) m_strIPAddr[i].Empty(); } CIOCPController::~CIOCPController(void) { // DeinitNetwork´Â »ó¼Ó¹Þ´Â ÃÖÁ¾ ¼­¹ö/Ŭ¶óÀÌ¾ðÆ® ¿¡¼­ ¸ÕÀú ¼±ÇàÇÏ¿© ÇØÁà¾ßÇÑ´Ù. // ÀÌÀ¯ : ÃÖÁ¾ »ó¼Ó´Ü¿¡¼­µµ ¶Ç Net_Receive µî°ú °°ÀÌ °¡»óÇÔ¼ö¸¦ Áö¿øÇϱ⠶§¹®¿¡ ÃÖÁ¾ »ó¼Ó´ÜÀÌ ¸ÕÀú ¼Ò¸êµÇ¸é(¶Ç´Â ¼Ò¸ê Áß)ÀÌ¸é ¿öÄ¿ ¾²·¹µå¿¡¼­ IO ó¸®ÇÏ´Â µµÁß¿¡ // Net_Receive µî¿¡¼­ SendMessage µî°ú °°Àº µ¿±âÈ­ Äڵ尡 Á¸ÀçÇϸé ÇàÀÌ °É¸®°í ´Ù¿îµÇ°Ô µÈ´Ù. //DeinitNetwork(); m_nExit = TRUE; // ¿öÄ¿¾²·¹µå¸¦ ¸ÕÀú Á×µµ·Ï µ¿±âÈ­ ÇÑ´Ù. // ÀÌÀ¯ : À§¿Í °°Àº ÀÌÀ¯·Î ÃÖÁ¾ »ó¼ÓÀÚ°¡ Handle¸¦ ÀÒ¾î¹ö¸®´Â ÀÏÀ» ¸·±â À§Çؼ­ if(m_EventExitWorkerThread != NULL) WaitForSingleObject(m_EventExitWorkerThread,INFINITE); if (m_pPerSocketCtxMemPool){ delete m_pPerSocketCtxMemPool; m_pPerSocketCtxMemPool = NULL; } if (m_pRecvMemPool){ delete m_pRecvMemPool; m_pRecvMemPool = NULL; } if (m_pSendMemPool){ delete m_pSendMemPool; m_pSendMemPool = NULL; } CloseHandle(m_hMutexLog); m_hMutexLog = NULL; if(m_EventExitConnectThread != NULL) { CloseHandle(m_EventExitConnectThread); m_EventExitConnectThread = NULL; } DeleteCriticalSection(&m_csContext); //TRACE("CIOCPController::~CIOCPController(void) \n"); } /*! * \brief * ¼ÒÄÏ ÃʱâÈ­ ÇÔ¼ö * * \returns * ½ÇÆÐ : FALSE, ¼º°ø : TRUE * * * ¼ÒÄÏÀ» ÃʱâÈ­Çϰí ÇöÀç È£½ºÆ®ÀÇ ¾ÆÀÌÇǸ¦ ¼³Á¤ÇÑ´Ù. * * \remarks * Write remarks for StartUp here. * * \see * Separate items with the '|' character. */ BOOL CIOCPController::StartUp() { // ¼ÒÄÏ ÃʱâÈ­ ó¸® if (!m_bIsStartUp) { WSADATA wsd; if(WSAStartup(MAKEWORD(2,2), &wsd) != 0) { return FALSE; } if (LOBYTE( wsd.wVersion ) != 2 || HIBYTE( wsd.wVersion ) != 2 ) { WSACleanup( ); return FALSE; } m_bIsStartUp = TRUE; } CHAR chName[255]; CHAR chAddr[128]; PHOSTENT pHostEntry; // IN_ADDR inAddr; CStringA strCurIP; strCurIP = _T(""); if( gethostname( chName, 255 ) != 0 ){ } else { if( ( pHostEntry = gethostbyname( chName ) ) != NULL ) { for (int i=0; pHostEntry->h_addr_list[i]; i++) { if(i >= 10) break; m_strIPAddr[i].Format(_T("%d.%d.%d.%d") , ((PUCHAR)pHostEntry->h_addr_list[i])[0] , ((PUCHAR)pHostEntry->h_addr_list[i])[1] , ((PUCHAR)pHostEntry->h_addr_list[i])[2] , ((PUCHAR)pHostEntry->h_addr_list[i])[3]); } // memcpy( &inAddr, pHostEntry->h_addr, 4 ); // memcpy(chAddr, inet_ntoa( inAddr ), 16); } } strCurIP = (CStringA)chAddr; m_strIP = strCurIP; return TRUE; } /*! * \brief * ¼ÒÄÏ ÇØÁ¦ ÇÔ¼ö * * \returns * TRUE * * * ¼ÒÄÏÀÇ »ç¿ëÀ» Á¾·áÇÏ°í ¹ÝȯÇÑ´Ù. * * \remarks * Write remarks for CleanUp here. * * \see * Separate items with the '|' character. */ BOOL CIOCPController::CleanUp() { // ¼ÒÄÏ »ç¿ë ³¡!!!!! if (m_bIsStartUp) WSACleanup(); m_bIsStartUp = FALSE; return TRUE; } /*! * \brief * ³×Æ®¿öÅ© ÃʱâÈ­ ÇÔ¼ö * * \param Mode * ³×Æ®¿öÅ© ¸ðµå ( ¼­¹ö , Ŭ¶óÀÌ¾ðÆ® ¸ðµå ) * * \param nSocketCount * »ý¼ºÇÒ ¼ÒÄÏÀÇ °³¼ö ( ¼­¹ö : ÃÖ´ë Ŭ¶óÀÌ¾ðÆ® °³¼ö, Ŭ¶óÀÌ¾ðÆ® : 1) * * \param nPort * Æ÷Æ® * * \param strIP * IPÁÖ¼Ò * * \param nWorkerThreadNum * IOCP ¿öÄ¿ ¾²·¹µå °³¼ö ¼³Á¤ ( ±âº»Àº 2 * ÇÁ·Î¼¼¼­¼ö + 1 * * \returns * ¼º°ø : TRUE, ½ÇÆÐ : FALSE * */ BOOL CIOCPController::InitNetwork(NetworkMode Mode, int nSocketCount, int nPort, CString strIP, int nWorkerThreadNum) { //TRACE("--- IOCP::Init() - Start! \n"); if (!m_bIsStartUp) return FALSE; if (!strIP.IsEmpty()) m_strIP = strIP; if (nPort > 0) m_nPort = nPort; if (m_nPort == 0) return FALSE; SOCKADDR_IN serverSockAddr; /********************************************************************************/ // Memory Pool ¸¸µé±â!! /********************************************************************************/ if (m_pPerSocketCtxMemPool){ delete m_pPerSocketCtxMemPool; m_pPerSocketCtxMemPool = NULL; } if (m_pRecvMemPool){ delete m_pRecvMemPool; m_pRecvMemPool = NULL; } if (m_pSendMemPool){ delete m_pSendMemPool; m_pSendMemPool = NULL; } m_pPerSocketCtxMemPool = new CMemPooler(nSocketCount * 2); //nSocketCount * 2 -> Block °³¼ö m_pRecvMemPool = new CMemPooler(nSocketCount * 2); m_pSendMemPool = new CMemPooler(nSocketCount * 2); if (!m_pPerSocketCtxMemPool || !m_pRecvMemPool || !m_pSendMemPool) { //TRACE("IOCP::Init() - Create Memory Pool Failed \n"); return FALSE; } m_NetMode = Mode; if (Mode == ServerMode) { m_bConnected = TRUE; /********************************************************************************/ // Listen Socket »ý¼º - Overlapped IO »ç¿ë /********************************************************************************/ if(m_ListenSocket != NULL) closesocket(m_ListenSocket); m_ListenSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED); if(m_ListenSocket == INVALID_SOCKET) { //TRACE("IOCP::Init() - Listen Socket Creation Failed : %d \n", WSAGetLastError()); return FALSE; } int nZero = 1; if (SOCKET_ERROR == setsockopt(m_ListenSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&nZero, sizeof(int))) { //TRACE("IOCP::Init() - setsockopt Fail : %d \n", WSAGetLastError()); closesocket(m_ListenSocket); m_ListenSocket = NULL; return FALSE; } serverSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); serverSockAddr.sin_family = AF_INET; serverSockAddr.sin_port = htons((short)m_nPort); // Bind if(bind(m_ListenSocket, (LPSOCKADDR)&serverSockAddr, sizeof(serverSockAddr))) { //TRACE("IOCP::Init() - Bind Failed : %d \n", WSAGetLastError()); closesocket(m_ListenSocket); m_ListenSocket = NULL; return FALSE; } // Listen if(SOCKET_ERROR == listen(m_ListenSocket, SOMAXCONN)) { //TRACE("IOCP::Init() - Change to Listen Mode Error : %d\n", WSAGetLastError()); closesocket(m_ListenSocket); m_ListenSocket = NULL; return FALSE; } } else if (Mode == ClientMode) { m_ListenSocket = INVALID_SOCKET; } /********************************************************************************/ // IOCP ÃʱâÈ­ ó¸® // m_hIOCP=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,nMaxNumberOfConcurrentThreads) /********************************************************************************/ int ErrCode; if (!Create(0, &ErrCode)) { //TRACE("IOCP::Init() - Create IO Completion Port Error: %d \n", ErrCode); return FALSE; } /********************************************************************************/ // Thread Pool À» »ý¼º! // BEGINTHREADEX(NULL,0,IocpWorkerThreadStartingPoint,piProcessThread,0,&dwThreadId) /********************************************************************************/ if (!CreateThreadPool(this,nWorkerThreadNum)) { //TRACE("IOCP::Init() - Create Thread Pool Failed \n"); return FALSE; } /********************************************************************************/ // Accept Thread »ý¼º. /********************************************************************************/ if (Mode == ServerMode) { DWORD dwThreadId; HANDLE hAccept = CreateThread(NULL, 0, AcceptThread, this, 0, &dwThreadId); CloseHandle(hAccept); hAccept = NULL; } return TRUE; } /*! * \brief * Accept ÀÛ¾÷ ó¸®!! * * * Ŭ¶óÀÌ¾ðÆ®·ÎºÎÅÍÀÇ Á¢¼Ó ¿¬°á ¿äûÀ» ó¸®ÇÏ´Â ÇÔ¼ö * */ void CIOCPController::AcceptProcess() { int ErrCode = 0; int sockaddr_size = sizeof(SOCKADDR_IN); SOCKADDR_IN clientsockaddr; SOCKET clientsocket = INVALID_SOCKET; pPerSocketContext pPerSocketCtx = NULL; //TRACE("IOCP::AcceptProcess() - Accept Process Start \n"); BOOL bLoop = TRUE; while(bLoop == TRUE) { Sleep(1); __try { clientsocket = INVALID_SOCKET; pPerSocketCtx = NULL; /********************************************************************************/ // Client·ÎºÎÅÍ accept /********************************************************************************/ clientsocket=accept(m_ListenSocket,(LPSOCKADDR)&clientsockaddr, &sockaddr_size); if(clientsocket==INVALID_SOCKET) { // ¸®½¼ ¼ÒÄÏÀ» Ŭ·ÎÁî Çϸé ÀÌ ¿¡·¯°¡ ³ª¿À¹Ç·Î // ÀÌ ¿¡·¯½Ã¿¡ Accept ·çÇÁ¸¦ ºüÁ®³ª°£´Ù. if(WSAGetLastError()==WSAEINTR || WSAGetLastError() == WSAENOTSOCK || WSAGetLastError() == WSANOTINITIALISED) { //TRACE("IOCP::AcceptProcess() - Accept Process End : %d\n",WSAGetLastError() ); bLoop = FALSE; return; // abnormalterminate ½ÇÇà } //TRACE("Accepting Client Error: %d\n ",WSAGetLastError()); __leave; } //TRACE("Client( IP: %s, Port: %d, Socket %d ) Connected\n",inet_ntoa(clientsockaddr.sin_addr),ntohs(clientsockaddr.sin_port), clientsocket); int nZero=0; if(SOCKET_ERROR==setsockopt(clientsocket,SOL_SOCKET,SO_RCVBUF,(const char*)&nZero,sizeof(int))) { //TRACE("Change Buffer Size Error, %d\n",WSAGetLastError()); return; } nZero=0; if(SOCKET_ERROR==setsockopt(clientsocket,SOL_SOCKET,SO_SNDBUF,(const char*)&nZero,sizeof(int))) { //TRACE("Change Buffer Size Error, %d\n",WSAGetLastError()); return; } /********************************************************************************/ // ¼ÒÄÏ ÄÁÅØ½ºÆ® ÇÒ´ç -> Completion Key // Per Socket Context ¸Þ¸ð¸® ÇÒ´ç /********************************************************************************/ pPerSocketCtx = AllocPerSocketContext(clientsocket); if(pPerSocketCtx == NULL) { //TRACE("Socket Context Allocation Error\n"); return; } /********************************************************************************/ // IOCP Ä¿³Î °´Ã¼¿Í ¿¬°á /********************************************************************************/ if (!Associate(clientsocket, reinterpret_cast(pPerSocketCtx), &ErrCode)) { //TRACE("IOCP::AcceptProcess() - Associating Error: %d\n ", ErrCode); return; } /********************************************************************************/ // Ãʱâ Recv ¿äû /********************************************************************************/ int nRet = AcceptedSocket(pPerSocketCtx, clientsockaddr.sin_addr.S_un.S_addr, m_nPort); if (nRet == 0) // ÀÌ¹Ì Á¢¼Ó. { //TRACE("IOCP::AcceptProcess() - Already Accepted! SocketContext[%X] ÀÌÀü ÄÁÅØ½ºÆ®¿Í »õ·Î¿î ÄÁÅØ½ºÆ®¸¦ ¸ðµÎ Áö¿î´Ù. !!!!!!!!\n",pPerSocketCtx); return; } else if (nRet == -1) { //TRACE("IOCP::AcceptProcess() - Accept Socket Error! \n"); return; } else { BOOL bRet = RecvPost(pPerSocketCtx); if(bRet == FALSE) { //TRACE("Init RecvPost Error\n"); return; } else { //TRACE("Init RevcPost Success\n"); __leave; } } } __finally { if (AbnormalTermination() == TRUE) { // ºñÁ¤»ó Á¾·á //TRACE("IOCP::AcceptProcess() - Called CloseSocket() in __finally! \n"); if (pPerSocketCtx != NULL) CloseSocket(pPerSocketCtx,FALSE,FALSE); if(clientsocket != INVALID_SOCKET) { closesocket(clientsocket); clientsocket = INVALID_SOCKET; } } else { // Á¤»ó»óȲ } } } } DWORD __stdcall CIOCPController::AcceptThread(PVOID pvParam) { CIOCPController* pCont = static_cast(pvParam); pCont->AcceptProcess(); return 0; } /********************************************************************************/ // /********************************************************************************/ /*! * \brief * Connect ÀÛ¾÷ ó¸® ÇÔ¼ö * * \param bReconnect * ÀÚµ¿ ÀçÁ¢¼Ó ¿©ºÎ(Ŭ¶óÀ̾ðÆ®) * * \returns * Á¢¼Ó ¼º°ø : TRUE, ½ÇÆÐ : FALSE * * ÀçÁ¢¼Ó ¸ðµåÀÏ °æ¿ì ConnectThread¸¦ »ý¼ºÇÏ¿© ÁÖ±âÀûÀ¸·Î ÀçÁ¢¼ÓÀ» ½ÃµµÇϸç\n * 1ȸ Á¢¼Ó ¸ðµåÀÏ °æ¿ì ConnectProcess ÇÔ¼ö¸¦ 1ȸ È£ÃâÇÑ´Ù. * */ BOOL CIOCPController::Connect(BOOL bReconnect) { m_bReconnect = bReconnect; if (!m_bReconnect) return ConnectProcess(); else { DWORD dwThreadId; HANDLE hConnect = CreateThread(NULL, 0, ConnectThread, this, 0, &dwThreadId); CloseHandle(hConnect); hConnect = NULL; } return TRUE; } /*! * \brief * Connect ÀÛ¾÷ ó¸®!! * * * ¼­¹ö·Î Á¢¼Ó ¿¬°á ¿äûÀ» ÇÏ´Â ÇÔ¼ö * */ BOOL CIOCPController::ConnectProcess() { m_EventExitConnectThread = CreateEvent(NULL, TRUE, FALSE, NULL); int ErrCode = 0; char chCurIP[32] = {0, }; m_straCurIP = m_strIP; sprintf_s(chCurIP, sizeof(chCurIP), m_straCurIP); SOCKET clientsocket = INVALID_SOCKET; int sockaddr_size = sizeof(SOCKADDR_IN); SOCKADDR_IN clientsockaddr; clientsockaddr.sin_family = AF_INET; clientsockaddr.sin_port = htons(m_nPort); clientsockaddr.sin_addr.S_un.S_addr = inet_addr(chCurIP); //TRACE("IOCP::ConnectProcess() - Connecting Started \n"); int retval; __try { do { Sleep(1); /********************************************************************************/ // Server¿¡ Connect /********************************************************************************/ retval = SOCKET_ERROR; if (!m_bConnected) { if(clientsocket != INVALID_SOCKET) closesocket(clientsocket); clientsocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED); if(clientsocket == INVALID_SOCKET) { //TRACE("IOCP::ConnectProcess() - SOCKET Create Failed \n"); return FALSE; } // ³íºí·°Å· Á¢¼Ó ½Ãµµ u_long non_blk = TRUE; if(SOCKET_ERROR == ioctlsocket(clientsocket, FIONBIO, &non_blk)) return TRUE; timeval timevalue; fd_set fdset; FD_ZERO(&fdset); FD_SET(clientsocket, &fdset); timevalue.tv_sec = 2; timevalue.tv_usec = 0; retval = connect(clientsocket, (SOCKADDR *)&clientsockaddr, sizeof(clientsockaddr)); ::select( (int)(clientsocket+1),NULL,&fdset,NULL,&timevalue); if( FD_ISSET(clientsocket,&fdset) == FALSE) { //TRACE("[CIOCPController::ConnectProcess()] connect Timeout \n"); retval = SOCKET_ERROR; } else { retval = TRUE; } non_blk = FALSE; if(SOCKET_ERROR == ioctlsocket(clientsocket, FIONBIO, &non_blk)) { closesocket(clientsocket); return FALSE; } if (retval == SOCKET_ERROR) closesocket(clientsocket); int n = WSAGetLastError(); //TRACE("[CIOCPController::ConnectProcess()] connect retrun[%d] LastError Code = [%d] \n",retval,n); } if (retval == SOCKET_ERROR) { if (m_bReconnect) { Sleep(500); continue; } else { //TRACE("Connect Process Á¾·á ¼º°ø - Á¢¼ÓX, ÀçÁ¢¼ÓX!\n"); return FALSE; } } EnterCriticalSection(&m_csContext); m_bConnected = TRUE; /********************************************************************************/ // ¼ÒÄÏ ÄÁÅØ½ºÆ® ÇÒ´ç -> Completion Key // Per Socket Context ¸Þ¸ð¸® ÇÒ´ç /********************************************************************************/ m_pSocketCtx = AllocPerSocketContext(clientsocket); if(m_pSocketCtx == NULL) { //TRACE("IOCP::AcceptProcess() - Socket Context Allocation Error \n"); closesocket(clientsocket); m_bConnected = FALSE; LeaveCriticalSection(&m_csContext); continue; } /********************************************************************************/ // IOCP Ä¿³Î °´Ã¼¿Í ¿¬°á /********************************************************************************/ if(Associate(clientsocket, reinterpret_cast(m_pSocketCtx), &ErrCode) == FALSE) { //TRACE("IOCP::AcceptProcess() - Associating Error: %d \n", ErrCode); LeaveCriticalSection(&m_csContext); CloseSocket(m_pSocketCtx,FALSE,FALSE); m_pSocketCtx = NULL; continue; } /********************************************************************************/ // Ãʱâ Recv ¿äû /********************************************************************************/ if(RecvPost(m_pSocketCtx) == FALSE) { //TRACE("IOCP::AcceptProcess() - Init RecvPost Error! \n "); LeaveCriticalSection(&m_csContext); CloseSocket(m_pSocketCtx,FALSE,FALSE); m_pSocketCtx = NULL; continue; } ConnectedSocket(m_pSocketCtx); LeaveCriticalSection(&m_csContext); } while (m_bReconnect); } __finally { if(AbnormalTermination() == TRUE) { // return À̳ª ¿¹¿Ü »óȲ¿¡¼­ ÀÌÂÊÀ¸·Î µé¾î¿È. //TRACE("IOCP::AcceptProcess() - Called CloseSocket() in __finally! \n"); if (m_pSocketCtx != NULL) { //LeaveCriticalSection(&m_csContext); CloseSocket(m_pSocketCtx,FALSE,FALSE); m_pSocketCtx = NULL; } SetEvent(m_EventExitConnectThread); //return FALSE; } else { //TRACE("Connect Process Á¾·á ¼º°ø!\n"); SetEvent(m_EventExitConnectThread); } OutputDebugString(_T("Connection Thread Á¾·á Á÷Àü __finally ·çƾ ¿Ï·á\n")); } OutputDebugString(_T("Connection Thread Á¾·á\n")); return TRUE; // jump out of __finally block has undefined behavior during termination handling } DWORD __stdcall CIOCPController::ConnectThread(PVOID pvParam) { CIOCPController* pCont = static_cast(pvParam); pCont->ConnectProcess(); return 0; } /********************************************************************************/ // /********************************************************************************/ //************************************ // Method: ProcessingThread // FullName: CIOCPController::ProcessingThread // Access: private // Returns: void // Qualifier: CIOCPHandler::IocpWorkerThreadStartingPoint(PVOID pvParam) ¿¡¼­ È£Ãâ // Parameter: void //************************************ /*! * \brief * Work Thread Function!!!!! * * * IOCP ¸Þ½ÃÁö 󸮸¦ À§ÇÑ ¿öÄ¿ ¾²·¹µå·Î½á\n * IOCP ¿¡ ¸Þ½ÃÁö°¡ ¹ß»ýÇÏ¸é ¾²·¹µå¸¦ ±ú¿ö¼­ ¸Þ½ÃÁö¸¦ ó¸®ÇÑ´Ù. * */ void CIOCPController::ProcessingThread(void) { pPerSocketContext pPerSocketCtx = NULL; pPerIoContext pPerIoCtx = NULL; DWORD dwBytesTransferred = 0; int ErrCode = 0; while (TRUE) { // IO Completion Packet ¾ò¾î¿Â´Ù. BOOL bRet = GetCompletionStatus(reinterpret_cast(&pPerSocketCtx), &dwBytesTransferred, reinterpret_cast(&pPerIoCtx), &ErrCode); try { if(bRet) { if(((__int64)pPerSocketCtx) == THREAD_DIE) { //TRACE("Thread[%d] IOCP::ProcessingThread() - THREAD_DIE! \n",GetCurrentThreadId()); break; } } if(m_nExit == TRUE) { //TRACE("ÀÌ¹Ì IOCP Controller Á¾·á µÊ. ¿öÄ¿¾²·¹µåµµ Á¾·á\n"); break; } if (dwBytesTransferred == 0) { //TRACE("Client Connection Closed\n"); throw "@@@ Client Connection Closed."; } ////TRACE("Thread[%d] Process Retrun[%d], pPerSocketCtxp[%X], pPerIOCtx[%X], dwBytesTransferred[%d] \n",GetCurrentThreadId(), bRet,pPerSocketCtx,pPerIoCtx,dwBytesTransferred); // ¿¡·¯ ó¸®. if(bRet) { if(NULL == pPerIoCtx) { //TRACE("IOCP::ProcessingThread() - Getting Completion Packet Failed %d \n",ErrCode); continue; } } else { if(NULL != pPerIoCtx) { // ¿©±â·Î ¿À¸é ¿¡·¯°¡ 64ÀÏ °¡´É¼ºÀÌ ³ô´Ù. // Áï ÁöÁ¤µÈ ³×Æ®¿öÅ© À̸§À» »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù. ÀÌ´Ù. // ¹¹ ÀÌ·²¶© ¼ÒÄÏ ²÷¾î¹ö¸®¸é ¸¸»ç OKÀÌ´Ù. CloseSocket(pPerSocketCtx); //TRACE("@@@ IOCP::ProcessingThread() - CloseSocket() in pPerIoCtx != NULL\r\n"); } continue; } // Ŭ¶óÀÌ¾ðÆ®°¡ ¿¬°á ²÷À½ if (dwBytesTransferred == 0) { //TRACE("Client Connection Closed\n"); throw "@@@ Client Connection Closed."; } // IO ¼º°Ý¿¡ µû¶ó ±×¿¡ µû¸¥ ó¸® if (pPerIoCtx == pPerSocketCtx->recvContext) { // RECV Operation //TRACE("-Thread[%d] recv IO Start\n",GetCurrentThreadId()); if (!RecvCompleteEvent(pPerSocketCtx, dwBytesTransferred)) { throw "RecvCompleteEvent Error\n"; } //TRACE("-Thread[%d] recv IO End\n",GetCurrentThreadId()); } else if (pPerIoCtx == pPerSocketCtx->sendContext) { // SEND Operation //TRACE("-Thread[%d] send IO Start\n",GetCurrentThreadId()); if(!SendCompleteEvent(pPerSocketCtx, dwBytesTransferred)) { throw "SendCompleteEvent Error\n"; } //TRACE("-Thread[%d] send IO End\n",GetCurrentThreadId()); } else { //TRACE("-Thread[%d] Other IO Start\n",GetCurrentThreadId()); if(!OtherCompleteEvent(pPerSocketCtx, dwBytesTransferred)) { throw "OtherCompleteEvent Error\n"; } //TRACE("-Thread[%d] Other IO End\n",GetCurrentThreadId()); } } catch (char* errText) { //TRACE("IOCP::ProcessingThread() - Exception \'%s , Next CloseSocket Call\n", errText); CloseSocket(pPerSocketCtx); } } InterlockedDecrement(&m_nLiveThreadNum); //TRACE("IOCP Worker Thread[%d] Exit ³²Àº ¾²·¹µå °³¼ö[%d]\n",GetCurrentThreadId(),m_nLiveThreadNum); if(m_nLiveThreadNum <= 0) { SetEvent(m_EventExitWorkerThread); } } /********************************************************************************/ // Recv ¿äû, Send ó¸®. // return °ª: TRUE -> ¿¡·¯ ¾øÀÌ Á¤»óÀûÀ¸·Î ó¸®µÊ // FALSE -> ¿Ï·á ÆÐŶ ó¸® µ¿ÀÛ Áß ¿¡·¯ ¹ß»ý // ¸®½Ãºê À̺¥Æ® ó¸® Çڵ鷯 ÇÔ¼ö /********************************************************************************/ /*! * \brief * ¸®½Ãºê À̺¥Æ® ó¸® Çڵ鷯 ÇÔ¼ö * * \param pPerSocketCtx * Recv ¼ÒÄÏ ÄÁÅØ½ºÆ® * * \param dwBytesTransferred * ¹ÞÀº ¹ÙÀÌÆ® ¼ö * * \returns * TRUE -> ¿¡·¯ ¾øÀÌ Á¤»óÀûÀ¸·Î 󸮵Ê\n * FALSE -> ¿Ï·á ÆÐŶ ó¸® µ¿ÀÛ Áß ¿¡·¯ ¹ß»ý */ BOOL CIOCPController::RecvCompleteEvent(pPerSocketContext pPerSocketCtx, DWORD dwBytesTransferred) { BOOL bRet = TRUE; WSABUF* pBuf = NULL; pPerSocketCtx->recvContext->ResetBuffer(); int nCount = 0; while(TRUE) { nCount++; pBuf = pPerSocketCtx->recvContext->GetBuffer(); if (pBuf != NULL) { //TRACE("Thread[%d] Socket[%d] RecvCompleted - Start\n",GetCurrentThreadId(), pPerSocketCtx->socket); bRet = RecvCompleted(pPerSocketCtx, dwBytesTransferred); // ´Ù ó¸®Çß´Ù°í °¡Á¤. //TRACE("Thread[%d] Socket[%d] RecvCompleted[%d] - End\n",GetCurrentThreadId(),bRet, pPerSocketCtx->socket); break; } if(nCount >= 1000) { //TRACE("[%d]¾Æ³ö¾¾¹ß..count[%d]\n",GetCurrentThreadId(),nCount); } Sleep(1); } if (bRet) pPerSocketCtx->recvContext->ReleaseBuffer(); // Buffer ÃʱâÈ­ else pPerSocketCtx->recvContext->UnlockBuffer(); // ´Ù½Ã Recv ¿äûÀ» Çϰí WTQ·Î µé¾î°£´Ù. return RecvPost(pPerSocketCtx); } /*! * \brief * Send ¿Ï·á ÆÐŶ ó¸® Çڵ鷯 ÇÔ¼ö * * \param pPerSocketCtx * Send ¼ÒÄÏ ÄÁÅØ½ºÆ® * * \param dwBytesTransferred * Àü¼ÛµÈ ¹ÙÀÌÆ® ¼ö * * \returns * TRUE -> ¿¡·¯ ¾øÀÌ Á¤»óÀûÀ¸·Î 󸮵Ê\n * FALSE -> ¿Ï·á ÆÐŶ ó¸® µ¿ÀÛ Áß ¿¡·¯ ¹ß»ý */ BOOL CIOCPController::SendCompleteEvent(pPerSocketContext pPerSocketCtx, DWORD dwBytesTransferred) { // Àü¼ÛµÈ Byte°¡ 0 º¸´Ù À۰ųª ÃÖ´ë ¹öÆÛº¸´Ù Å©¸é ¿À·ù if (dwBytesTransferred < 0 || dwBytesTransferred > MAX_BUFFER_SIZE) { pPerSocketCtx->sendContext->ReleaseBuffer(); ////TRACE("Error : SendCompleteEvent. Trans Size Mismatch %d", dwBytesTransferred); return FALSE; } WSABUF* pBuf = pPerSocketCtx->sendContext->GetLockedBuffer(); if (dwBytesTransferred < static_cast(pPerSocketCtx->sendContext->GetLen())) { // ¸ðµÎ º¸³»ÁöÁö ¾Ê¾Ò±â ¶§¹®¿¡ ÀçÀü¼Û. if (!pBuf) { //TRACE("Buffer Error : SendCompleteEvent \n"); return FALSE; } // //TRACE("SendPost Size Mismatch %d, Sent %d", pBuf->len, dwBytesTransferred); pBuf->buf += dwBytesTransferred; pBuf->len -= dwBytesTransferred; SendPost(pPerSocketCtx); } else { SendCompleted(pPerSocketCtx, dwBytesTransferred); pPerSocketCtx->sendContext->ReleaseBuffer(); } return TRUE; } /*! * \brief * ¸Þ½ÃÁö ¼ö½Å ºÎ * * \param pPerSocketCtx * ¼ö½ÅµÈ ÄÁÅØ½ºÆ® * * \returns * ¼º°ø : TRUE, ½ÇÆÐ : FALSE * * \throws * return FALSE * * IOCP -> Work Thread -> Recv ¼ö½Å -> RecvPost * */ BOOL CIOCPController::RecvPost(pPerSocketContext pPerSocketCtx) { DWORD dwRecvBytes = 0; DWORD dwFlags = 0; try { // ¼ö½Å. WSABUF* pBuf = pPerSocketCtx->recvContext->GetLockedBuffer(); WSAOVERLAPPED* pOverlapped = pPerSocketCtx->recvContext->GetOverlapped(); if (!pBuf || !pOverlapped) return FALSE; // ÄÁÅØ½ºÆ®·ÎºÎÅÍ ¹öÆÛ¸¦ Àоî¿Â´Ù. int ret = WSARecv(pPerSocketCtx->socket, pBuf, 1, &dwRecvBytes, &dwFlags, pOverlapped, NULL); if(SOCKET_ERROR == ret) { int ErrCode = WSAGetLastError(); if(ErrCode != WSA_IO_PENDING && ErrCode != WSAEWOULDBLOCK) { //TRACE("IOCP::RecvPost() - WSARecv() Failed: %d, %d \n", ErrCode, pPerSocketCtx->recvContext->GetLen()); return FALSE; } } } catch(...) { //TRACE("IOCP::RecvPost() - Exception \n"); return FALSE; } return TRUE; } /*! * \brief * ¸Þ½ÃÁö ¼Û½Å ¿äû ºÎ * * \param pPerSocketCtx * ¼Û½ÅÇÒ ÄÁÅØ½ºÆ® * * \returns * ¼º°ø : TRUE, ½ÇÆÐ : FALSE * * \throws * return FALSE * * IOCP * * */ int CIOCPController::SendPost(pPerSocketContext pPerSocketCtx) { if (!pPerSocketCtx) return 0; int iSend; DWORD dwSended;//, dwIOBytes, dwTotBytes; try { // Size ÃʱâÈ­. WSABUF* pBuf = pPerSocketCtx->sendContext->GetLockedBuffer(); WSAOVERLAPPED* pOverlapped = pPerSocketCtx->sendContext->GetOverlapped(); if (!pBuf || !pOverlapped) return 0; pPerSocketCtx->sendContext->ResetOverlapped(); // Àü¼Û. dwSended = 0; iSend = WSASend(pPerSocketCtx->socket, pBuf, 1, &(dwSended), 0, pOverlapped, NULL); if (SOCKET_ERROR == iSend) // ErrorÀÏ °æ¿ì´Â Break; { int nError = WSAGetLastError(); if (WSA_IO_PENDING == nError || WSAEWOULDBLOCK == nError) { // //TRACE("WSASend() Error : %d", nError); } else if (nError == WSAECONNRESET) // Á¢¼Ó Àç¼³Á¤(Á¾·á) { //TRACE("WSASend() - WSAECONNRESET \n"); CloseSocket(pPerSocketCtx); } else { //TRACE("WSASend() - Unknown Error : %d \n", nError); return 1; } } else { if (dwSended == 0) // º¸³½ Bytes ¼ö°¡ 0ÀÏ °æ¿ì Break; return 2; } } catch(...) { //TRACE("IOCP::SendPost() - Exception \n"); return 0; } return 1; } /*! * \brief * ¸Þ½ÃÁö ¼Û½Å ¿äû ºÎ * * \param pPerSocketCtx * Description of parameter pPerSocketCtx. * * \param pBuffer * ¼Û½ÅÇÒ ¹öÆÛ * * \param nLen * ¹öÆÛÀÇ ±æÀÌ Á¤º¸ * * \returns * ¼º°ø : TRUE, ½ÇÆÐ : FALSE * * \throws * Description of criteria for throwing this exception. * * pBuffer ³»¿ëÀ» ¼ÒÄÏ¿¡ ´ã¾Æ¼­ ¼Û½ÅÇÑ´Ù. * */ int CIOCPController::SendPost(pPerSocketContext pPerSocketCtx, void* pBuffer, int nLen) { WSABUF* pBuf = pPerSocketCtx->sendContext->GetLockedBuffer(); if (!pBuf) return 0; if (nLen > MAX_BUFFER_SIZE) return 0; memcpy(pBuf->buf, pBuffer, nLen); pBuf->len = nLen; pPerSocketCtx->sendContext->UnlockBuffer(); return SendPost(pPerSocketCtx); } /*! * \brief * Recv, Send ¿Ï·á µ¿ÀÛ ¿ÜÀÇ Ã³¸® Çڵ鷯 ÇÔ¼ö * * \param pPerSocketCtx * ¼ÒÄÏ ÄÁÅØ½ºÆ® * * \param dwBytesTransferred * ¹ÞÀº ¹ÙÀÌÆ® ¼ö * * \returns * FALSE * \throws * Description of criteria for throwing this exception. * * ¿©±â·Î µé¾î¿À´Â À̺¥Æ®´Â Send, Recv ÀÌ¿ÜÀÇ ¸Þ½ÃÁö·Î ¼ÒÄÏÀ» ´Ý°í FALSE¸¦ ¹ÝȯÇÑ´Ù. * */ BOOL CIOCPController::OtherCompleteEvent(pPerSocketContext pPerSocketCtx, DWORD dwBytesTransferred) { // ÇöÀç ¿©±â·Î ¿À¸é Recv , Send ÀÌ¿ÜÀÇ ÀÌ»óÇÑ µ¿ÀÛÀ» °¡¸®Å´ ¼ÒÄÏ ²÷¾î¹ö¸®ÀÚ. CloseSocket(pPerSocketCtx); return FALSE; // ¿¡·¯¸¦ °¡¶óÅ´ } /********************************************************************************/ // /********************************************************************************/ /*! * \brief * Ŭ¶óÀÌ¾ðÆ® ¼ÒÄÏ ÄÁÅØ½ºÆ® Á¦°ÅÇÏ°í ¼ÒÄÏ ´ÝÀ½ * * \param pPerSocketCtx * ´ÝÀ» ¼ÒÄÏ * * \param bGraceful * TRUE : Á¤»ó ÇÁ·Î¼¼½º·Î ¼ÒÄÏ ÇØÁ¦ \n * FALSE : °­Á¦ ¼ÒÄÏ ÇØÁ¦ * * \param bNotify * TRUE : ¼ÒÄÏÀÌ ²÷¾îÁ³À»À½ Class¿¡ ÅëÁöÇÑ´Ù. * */ void CIOCPController::CloseSocket(pPerSocketContext pPerSocketCtx, BOOL bGraceful, BOOL bNotify) { EnterCriticalSection(&m_csContext); //TRACE("Call! CloseSocket \n"); if (!pPerSocketCtx) { if (m_NetMode == ClientMode && m_bConnected == TRUE) { m_bConnected = FALSE; //TRACE("CloseSocket ÄÁÅØ½ºÆ®¾øÀ½ : Client Mode m_bConnected[%d] \n",m_bConnected); } LeaveCriticalSection(&m_csContext); return; } try { //TRACE("CloseSocket ; %d, Socket %d, this %d\n", reinterpret_cast(pPerSocketCtx), pPerSocketCtx->socket, reinterpret_cast(this)); if(pPerSocketCtx != NULL) { if (m_NetMode == ClientMode && !m_bConnected) { LeaveCriticalSection(&m_csContext); return; } if (pPerSocketCtx->socket != INVALID_SOCKET) { // SocketÀÌ ²÷¾îÁ³À½À» »ó¼ÓÇÏ´Â Class¿¡ ¾Ë·ÁÁØ´Ù. //TRACE("-- Notify Call -- \n"); if (bNotify) SocketClosed(pPerSocketCtx); //TRACE("-- Notify End -- \n"); if(!bGraceful) { LINGER LingerStruct; LingerStruct.l_onoff = 1; LingerStruct.l_linger = 0; // closesocketÀº °ð¹Ù·Î ¸®ÅÏÇÏ°í ¼Û½Å ¹öÆÛÀÇ µ¥ÀÌÅÍ´Â »èÁ¦ÇÑ ÈÄ TCP ¿¬°áÀ» °­Á¦ Á¾·áÇÑ´Ù. setsockopt(pPerSocketCtx->socket, SOL_SOCKET, SO_LINGER, (char*)&LingerStruct, sizeof(LingerStruct)); } // ¼ÒÄÏ ´Ý°í ¸Þ¸ð¸® ¹Ýȯ //TRACE("´Ý°í ½ÍÀº ¼ÒÄÏ[%d] \n",pPerSocketCtx->socket); int nRet = closesocket(pPerSocketCtx->socket); if(nRet != 0) { //TRACE("closesocket retrun error %d Code[%d] \n",nRet,WSAGetLastError()); } pPerSocketCtx->socket = INVALID_SOCKET; DeallocPerSocketContext(pPerSocketCtx); } pPerSocketCtx = NULL; if (m_NetMode == ClientMode) { m_bConnected = FALSE; //TRACE("CloseSocket Client Mode m_bConnected[%d] \n",m_bConnected); } } LeaveCriticalSection(&m_csContext); } catch(...) { //TRACE("CloseSocket Exception!!! \n"); LeaveCriticalSection(&m_csContext); return; } } /*! * \brief * IOCP ¼­¹ö Á¤Áö * * IOCP ¼­¹ö¸¦ Á¤ÁöÇÏ´Â ÇÔ¼ö·Î \n * 1. ¸ðµç IOCP ¾²·¹µåÀÇ Á¤Áö(ÃÖ¿ì¼±) * 2. ¼­¹ö¸ðµå - Listen ¼ÒÄÏÀ» ÇØÁ¦ * 3. Ŭ¶óÀÌ¾ðÆ®¸ðµå - ConnectionThread°¡ »ì¾ÆÀÖÀ¸¸é Á¾·á ÈÄ ¼ÒÄÏ ÇØÁ¦ * * \remarks * IOCP ¿öÄ¿ ¾²·¹µå´Â ÃÖ¿ì¼±À¸·Î Á×ÀδÙ. * */ void CIOCPController::DeinitNetwork() { //TRACE("--- IOCP::CIOCPController::DeinitNetwork() Start \n"); m_bReconnect = FALSE; CloseAllThreads(); if (m_NetMode == ServerMode) { m_bConnected = FALSE; closesocket(m_ListenSocket); m_ListenSocket = INVALID_SOCKET; } else if(m_NetMode == ClientMode) { if(m_EventExitConnectThread != NULL) WaitForSingleObject(m_EventExitConnectThread, INFINITE); if (m_bConnected) { CloseSocket(m_pSocketCtx); m_pSocketCtx = NULL; } m_bConnected = FALSE; } //TRACE("--- IOCP::CIOCPController::DeinitNetwork() End \n"); } ////////////////////////////////////////////////////////////// // ¿¡·¯¸Þ½ÃÁö, µð¹ö±ë // µð¹ö±× Ãâ·Â void CIOCPController::NoticeMsg(char *str, ...) { }