I want to write a server using a workflow pool and an I / O completion port. The server must process and forward messages between multiple clients. The data per client is in the ClientContext class. Data between instances of this class is exchanged using workflows. I think this is a typical scenario.
However, I have two problems with these I / O completion ports.
(1) The first problem is that the server mainly receives data from clients, but I never know if a complete message has been received. In fact, WSAGetLastError () always returns that WSARecv () is still waiting. I tried to wait for the OVERLAPPED.hEvent event with WaitForMultipleObjects (). However, it is blocked forever, i.e. WSARecv () never terminates in my program. My goal is to be absolutely sure that the entire message is received before further processing begins. My message has a "message length" field in its header, but I don’t see how to use it with the parameters of the IOCP function.
(2) If WSARecv () is commented out in the code snippet below, the program still receives data. What does it mean? Does this mean that I don’t need to call WSARecv () at all? I cannot get deterministic behavior with these I / O completion ports. Thanks for your help!
while(WaitForSingleObject(module_com->m_shutdown_event, 0)!= WAIT_OBJECT_0) { dequeue_result = GetQueuedCompletionStatus(module_com->m_h_io_completion_port, &transfered_bytes, (LPDWORD)&lp_completion_key, &p_ol, INFINITE); if (lp_completion_key == NULL) { //Shutting down break; } //Get client context current_context = (ClientContext *)lp_completion_key; //IOCP error if(dequeue_result == FALSE) { //... do some error handling... } else { // 'per client' data thread_state = current_context->GetState(); wsa_recv_buf = current_context->GetWSABUFPtr(); // 'per call' data this_overlapped = current_context->GetOVERLAPPEDPtr(); } while(thread_state != STATE_DONE) { switch(thread_state) { case STATE_INIT: //Check if completion packet has been posted by internal function or by WSARecv(), WSASend() if(transfered_bytes > 0) { dwFlags = 0; transf_now = 0; transf_result = WSARecv(current_context->GetSocket(), wsa_recv_buf, 1, &transf_now, &dwFlags, this_overlapped, NULL); if (SOCKET_ERROR == transf_result && WSAGetLastError() != WSA_IO_PENDING) { //...error handling... break; } // put received message into a message queue } else // (transfered_bytes == 0) { // Another context passed data to this context // and notified it via PostQueuedCompletionStatus(). } break; } } }
source share