/////////////////////////////////////////////////////////// // 비동기 입력 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; } }
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; } }
void IOThread::DoIocpJob() { DWORD dwTransferred = 0; OverlappedIOContext* context = nullptr; ULONG_PTR completionKey = 0; int ret = GetQueuedCompletionStatus( mCompletionPort, &dwTransferred, (PULONG_PTR)&completionKey, (LPOVERLAPPED*)&context, GQCS_TIMEOUT ); if ( completionKey == THREAD_QUIT_KEY ) { mIsContinue = false; return; } ClientSession* session = context ? context->mSessionObject : nullptr; if ( ret == 0 || dwTransferred == 0 ) { int gle = GetLastError(); /// check time out first if ( gle == WAIT_TIMEOUT && context == nullptr ) { return; } if ( context->mIoType == IO_RECV || context->mIoType == IO_SEND ) { CRASH_ASSERT( nullptr != session ); /// In most cases in here: ERROR_NETNAME_DELETED(64) session->DisconnectRequest( DR_COMPLETION_ERROR ); DeleteIoContext( context ); return; } } CRASH_ASSERT( nullptr != session ); bool completionOk = false; switch ( context->mIoType ) { case IO_CONNECT: session->ConnectCompletion(); completionOk = true; break; case IO_DISCONNECT: session->DisconnectCompletion( static_cast<OverlappedDisconnectContext*>( context )->mDisconnectReason ); completionOk = true; break; case IO_RECV_ZERO: completionOk = session->PostRecv(); break; case IO_SEND: session->SendCompletion( dwTransferred ); if ( context->mWsaBuf.len != dwTransferred ) printf_s( "Partial SendCompletion requested [%d], sent [%d]\n", context->mWsaBuf.len, dwTransferred ); else completionOk = true; break; case IO_RECV: session->RecvCompletion( dwTransferred ); // 일단 테스트용 에코! // session->EchoBack(); completionOk = session->PreRecv(); break; default: printf_s( "Unknown I/O Type: %d\n", context->mIoType ); CRASH_ASSERT( false ); break; } if ( !completionOk ) { /// connection closing session->DisconnectRequest( DR_IO_REQUEST_ERROR ); } DeleteIoContext( context ); }