void CALLBACK RecvCompletion(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags) { ClientSession* fromClient = static_cast<OverlappedIO*>(lpOverlapped)->mObject; fromClient->DecRefCount(); if (!fromClient->IsConnected()) return; /// 에러 발생시 해당 세션 종료 if (dwError || cbTransferred == 0) { fromClient->Disconnect(); return; } /// 받은 데이터 처리 fromClient->OnRead(cbTransferred); /// 다시 받기 if (false == fromClient->PostRecv()) { fromClient->Disconnect(); return; } }
/////////////////////////////////////////////////////////// // 비동기 입력 WSARecv()에 의해서, 입력이 완료 되면 콜백으로 RecvCompletion 실행 void CALLBACK RecvCompletion( DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags ) { // lpOverlapped 인자를 OverlappedIO 형태로 형변환 하면 // 해당 구조체의 멤버 변수 mObject => ClientSession* // 바로 이 포인터가 비동기 입력 WSARecv로 보낸 ClientSession 객체의 주소값 // PostRecv 멤소드에서 mOverlappedRecv.mObject = this ; 이 부분 참조 ClientSession* fromClient = static_cast<OverlappedIO*>( lpOverlapped )->m_Object; // Overlapped IO 완료 했음. 카운트 감소 fromClient->DecOverlappedRequest(); if ( !fromClient->IsConnected() ) return; /// 에러 발생시 해당 세션 종료 if ( dwError || cbTransferred == 0 ) { LogD( "[Disconnected from:]ClientSession::RecvCompletion dwError \n" ); fromClient->Disconnect(); return; } /// 받은 데이터 처리 fromClient->OnRead( cbTransferred ); /// 다시 받기 if ( false == fromClient->PostRecv() ) { LogD( "[Disconnected from:]ClientSession::RecvCompletion PostRecv \n" ); fromClient->Disconnect(); return; } }
unsigned int WINAPI IocpManager::IoWorkerThread(LPVOID lpParam) { LThreadType = THREAD_IO_WORKER; LIoThreadId = reinterpret_cast<int>(lpParam); HANDLE hComletionPort = GIocpManager->GetComletionPort(); while (true) { DWORD dwTransferred = 0; OverlappedIOContext* context = nullptr; ClientSession* asCompletionKey = nullptr; int ret = 0; ///<여기에는 GetQueuedCompletionStatus(hComletionPort, ..., GQCS_TIMEOUT)를 수행한 결과값을 대입 /// check time out first if (ret == 0 && GetLastError()==WAIT_TIMEOUT) continue; if (ret == 0 || dwTransferred == 0) { /// connection closing asCompletionKey->Disconnect(DR_RECV_ZERO); GSessionManager->DeleteClientSession(asCompletionKey); continue; } // if (nullptr == context) 인 경우 처리 //{ //} bool completionOk = true; switch (context->mIoType) { case IO_SEND: completionOk = SendCompletion(asCompletionKey, context, dwTransferred); break; case IO_RECV: completionOk = ReceiveCompletion(asCompletionKey, context, dwTransferred); break; default: printf_s("Unknown I/O Type: %d\n", context->mIoType); break; } if ( !completionOk ) { /// connection closing asCompletionKey->Disconnect(DR_COMPLETION_ERROR); GSessionManager->DeleteClientSession(asCompletionKey); } } return 0; }
unsigned int WINAPI IOCP_Manager::IoWorkerThread(LPVOID lpParam) { LThreadType = THREAD_TYPE::THREAD_IO_WORKER; LIoThreadID = reinterpret_cast<int>(lpParam); HANDLE hCompletionPort = GIOCP_Manager->GetCompletionPort(); while (true) { DWORD dwTransferred = 0; OverlappedIOContext* context = nullptr; ClientSession* asCompletionKey = nullptr; int ret = GetQueuedCompletionStatus(hCompletionPort, &dwTransferred, (ULONG_PTR*)&asCompletionKey, (LPOVERLAPPED*)&context, GQCS_TIMEOUT); if (ret == 0 && GetLastError() == WAIT_TIMEOUT) { continue; } if (ret == 0 || dwTransferred == 0) { asCompletionKey->Disconnect(DisconnectReason::DR_RECV_ZERO); GSessionManager->DeleteClientSession(asCompletionKey); continue; } if (context == nullptr) { printf_s("not dequeue completion packet\n"); continue; } bool completionOk = true; switch (context->mIoType) { case IOType::IO_SEND: completionOk = SendCompletion(asCompletionKey, context, dwTransferred); break; case IOType::IO_RECV: completionOk = ReceiveCompletion(asCompletionKey, context, dwTransferred); break; default: printf_s("Unkonw I/O type: %d\n", context->mIoType); break; } if (!completionOk) { asCompletionKey->Disconnect(DisconnectReason::DR_COMPLETION_ERROR); GSessionManager->DeleteClientSession(asCompletionKey); } } return 0; }
bool IOCP_Manager::StartAcceptLoop() { if (listen(mListenSocket, SOMAXCONN) == SOCKET_ERROR) { printf_s("Listen Error\n"); return false; } while (true) { SOCKET acceptedSock = accept(mListenSocket, NULL, NULL); if (acceptedSock == SOCKET_ERROR) { printf_s("accept : invalid socket\n"); continue; } SOCKADDR_IN clientaddr; int addrlen = sizeof(SOCKADDR_IN); getpeername(acceptedSock, (SOCKADDR*)&clientaddr, &addrlen); ClientSession* client = GSessionManager->CreateClientSession(acceptedSock); if (client->OnConnect(&clientaddr) == false) { client->Disconnect(DisconnectReason::DR_CONNECT_ERROR); GSessionManager->DeleteClientSession(client); } } return true; }
bool IocpManager::StartAcceptLoop() { /// listen if (SOCKET_ERROR == listen(mListenSocket, SOMAXCONN)) return false; /// accept loop while (true) { SOCKET acceptedSock = accept(mListenSocket, NULL, NULL); if (acceptedSock == INVALID_SOCKET) { printf_s("accept: invalid socket\n"); continue; } SOCKADDR_IN clientaddr; int addrlen = sizeof(clientaddr); getpeername(acceptedSock, (SOCKADDR*)&clientaddr, &addrlen); /// 소켓 정보 구조체 할당과 초기화 ClientSession* client = GSessionManager->CreateClientSession(acceptedSock); /// 클라 접속 처리 if (false == client->OnConnect(&clientaddr)) { client->Disconnect(DR_ONCONNECT_ERROR); GSessionManager->DeleteClientSession(client); } } return true; }
void ClientManager::FlushClientSend() { for (auto& it : mClientList) { ClientSession* client = it.second; if (false == client->SendFlush()) { client->Disconnect(); } } }
unsigned int WINAPI ClientHandlingThread( LPVOID lpParam ) { LThreadType = THREAD_CLIENT ; HANDLE hEvent = (HANDLE)lpParam ; /// Timer HANDLE hTimer = CreateWaitableTimer(NULL, FALSE, NULL) ; if (hTimer == NULL) return -1 ; LARGE_INTEGER liDueTime ; liDueTime.QuadPart = -10000000 ; ///< 1초 후부터 동작 if ( !SetWaitableTimer(hTimer, &liDueTime, 1, TimerProc, NULL, TRUE) ) return -1 ; while ( true ) { /// accept or IO/Timer completion 대기 DWORD result = WaitForSingleObjectEx(hEvent, INFINITE, TRUE) ; /// client connected if ( result == WAIT_OBJECT_0 ) { /// 소켓 정보 구조체 할당과 초기화 ClientSession* client = g_client_manager->CreateClient(g_AcceptedSocket) ; SOCKADDR_IN clientaddr ; int addrlen = sizeof(clientaddr) ; getpeername(g_AcceptedSocket, (SOCKADDR*)&clientaddr, &addrlen) ; // 클라 접속 처리 if ( false == client->OnConnect(&clientaddr) ) { client->Disconnect() ; } continue ; ///< 다시 대기로 } // APC에 있던 completion이 아니라면 에러다 if ( result != WAIT_IO_COMPLETION ) return -1 ; } CloseHandle( hTimer ) ; return 0; }
unsigned int WINAPI ClientHandlingThread( LPVOID lpParam ) { LThreadType = THREAD_CLIENT; PendingAcceptList* pAcceptList = (PendingAcceptList*)lpParam; /// Timer HANDLE hTimer = CreateWaitableTimer( NULL, FALSE, NULL ); if ( hTimer == NULL ) return -1; LARGE_INTEGER liDueTime; liDueTime.QuadPart = -10000000; ///< 1초 후부터 동작 if ( !SetWaitableTimer( hTimer, &liDueTime, 100, TimerProc, NULL, TRUE ) ) return -1; while ( true ) { SOCKET acceptSock = NULL; /// 새로 접속한 클라이언트 처리 if ( pAcceptList->Consume( acceptSock, false ) ) { /// 소켓 정보 구조체 할당과 초기화 ClientSession* client = GClientManager->CreateClient( acceptSock ); SOCKADDR_IN clientaddr; int addrlen = sizeof( clientaddr ); getpeername( acceptSock, (SOCKADDR*)&clientaddr, &addrlen ); // 클라 접속 처리 if ( false == client->OnConnect( &clientaddr ) ) { client->Disconnect(); } continue; ///< 다시 대기로 } /// 최종적으로 클라이언트들에 쌓인 send 요청 처리 GClientManager->FlushClientSend(); /// APC Queue에 쌓인 작업들 처리 SleepEx( INFINITE, TRUE ); } CloseHandle( hTimer ); return 0; }
void CALLBACK SendCompletion( DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags ) { ClientSession* fromClient = static_cast<OverlappedIO*>(lpOverlapped)->mObject; fromClient->DecOverlappedRequest(); if ( !fromClient->IsConnected() ) return; /// 에러 발생시 해당 세션 종료 if ( dwError || cbTransferred == 0 ) { fromClient->Disconnect(); return; } fromClient->OnWriteComplete(cbTransferred); }
// 비동기 출력 WSASend()에 의해서 출력이 완료 되면 콜백으로 SendCompletion 실행 void CALLBACK SendCompletion( DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags ) { ClientSession* fromClient = static_cast<OverlappedIO*>( lpOverlapped )->m_Object; // Overlapped IO 완료 했음. 카운트 감소 fromClient->DecOverlappedRequest(); if ( !fromClient->IsConnected() ) { return; } /// 에러 발생시 해당 세션 종료 if ( dwError || cbTransferred == 0 ) { LogD( "[Disconnected from:]ClientSession::SendCompletion dwError \n" ); fromClient->Disconnect(); return; } /// 보내기 완료한 데이터를 버퍼에서 제거 fromClient->OnWriteComplete( cbTransferred ); }
unsigned int WINAPI IocpManager::IoWorkerThread(LPVOID lpParam) { LThreadType = THREAD_IO_WORKER; LIoThreadId = reinterpret_cast<int>(lpParam); HANDLE hCompletionPort = GIocpManager->GetCompletionPort(); printf_s("Started thread for completion port %d \n", hCompletionPort); while (true) { DWORD dwTransferred = 0; OverlappedIOContext* context = nullptr; ClientSession* asCompletionKey = nullptr; int ret = GetQueuedCompletionStatus( hCompletionPort, // _In_ HANDLE CompletionPort, &dwTransferred, // Out_ LPDWORD lpNumberOfBytes, (PULONG_PTR)&asCompletionKey, // _Out_ PULONG_PTR lpCompletionKey, (LPOVERLAPPED*)&context, // _Out_ LPOVERLAPPED *lpOverlapped, GQCS_TIMEOUT // _In_ DWORD dwMilliseconds ); /// check time out first if (ret == 0 && GetLastError()==WAIT_TIMEOUT) continue; if (ret == 0 || dwTransferred == 0) { /// connection closing asCompletionKey->Disconnect(DR_RECV_ZERO); GSessionManager->DeleteClientSession(asCompletionKey); continue; } if (context == nullptr) { asCompletionKey->Disconnect(DR_RECV_ZERO); GSessionManager->DeleteClientSession(asCompletionKey); } bool completionOk = true; switch (context->mIoType) { case IO_SEND: completionOk = SendCompletion(asCompletionKey, context, dwTransferred); break; case IO_RECV: completionOk = ReceiveCompletion(asCompletionKey, context, dwTransferred); break; default: printf_s("Unknown I/O Type: %d\n", context->mIoType); break; } if ( !completionOk ) { /// connection closing asCompletionKey->Disconnect(DR_COMPLETION_ERROR); GSessionManager->DeleteClientSession(asCompletionKey); } } return 0; }