Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to detect WinSock TCP timeout with BindIoCompletionCallback
    text
    copied!<p>I am building a Visual C++ WinSock TCP server using BindIoCompletionCallback, it works fine receiving and sending data, but I can't find a good way to detect timeout: SetSockOpt/SO_RCVTIMEO/SO_SNDTIMEO has no effect on nonblocking sockets, if the peer is not sending any data, the CompletionRoutine is not called at all.</p> <p>I am thinking about using RegisterWaitForSingleObject with the hEvent field of OVERLAPPED, that might work but then CompletionRoutine is not needed at all, am I still using IOCP ? is there a performance concern if I use only RegisterWaitForSingleObject and not using BindIoCompletionCallback ?</p> <p>Update: Code Sample:</p> <p>My first try:</p> <pre><code> bool CServer::Startup() { SOCKET ServerSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED); WSAEVENT ServerEvent = WSACreateEvent(); WSAEventSelect(ServerSocket, ServerEvent, FD_ACCEPT); ...... bind(ServerSocket......); listen(ServerSocket......); _beginthread(ListeningThread, 128 * 1024, (void*) this); ...... ...... } void __cdecl CServer::ListeningThread( void* param ) // static { CServer* server = (CServer*) param; while (true) { if (WSAWaitForMultipleEvents(1, &amp;server-&gt;ServerEvent, FALSE, 100, FALSE) == WSA_WAIT_EVENT_0) { WSANETWORKEVENTS events = {}; if (WSAEnumNetworkEvents(server-&gt;ServerSocket, server-&gt;ServerEvent, &amp;events) != SOCKET_ERROR) { if ((events.lNetworkEvents &amp; FD_ACCEPT) &amp;&amp; (events.iErrorCode[FD_ACCEPT_BIT] == 0)) { SOCKET socket = accept(server-&gt;ServerSocket, NULL, NULL); if (socket != SOCKET_ERROR) { BindIoCompletionCallback((HANDLE) socket, CompletionRoutine, 0); ...... } } } } } } VOID CALLBACK CServer::CompletionRoutine( __in DWORD dwErrorCode, __in DWORD dwNumberOfBytesTransfered, __in LPOVERLAPPED lpOverlapped ) // static { ...... BOOL res = GetOverlappedResult(......, TRUE); ...... } class CIoOperation { public: OVERLAPPED Overlapped; ...... ...... }; bool CServer::Receive(SOCKET socket, PBYTE buffer, DWORD length, void* context) { if (connection != NULL) { CIoOperation* io = new CIoOperation(); WSABUF buf = {length, (PCHAR) buffer}; DWORD flags = 0; if ((WSARecv(Socket, &amp;buf, 1, NULL, &amp;flags, &amp;io-&gt;Overlapped, NULL) != 0) &amp;&amp; (GetLastError() != WSA_IO_PENDING)) { delete io; return false; } else return true; } return false; } </code></pre> <p>As I said, it works fine if the client is actually sending data to me, 'Receive' is not blocking, CompletionRoutine got called, data received, but here is one gotcha, if the client is not sending any data to me, how can I give up after a timeout ?</p> <p>Since SetSockOpt/SO_RCVTIMEO/SO_SNDTIMEO wont help here, I think I should use the hEvent field in the OVERLAPPED stucture which will be signaled when the IO completes, but a WaitForSingleObject / WSAWaitForMultipleEvents on that will block the Receive call, and I want the Receive to always return immediately, so I used RegisterWaitForSingleObject and WAITORTIMERCALLBACK. it worked, the callback got called after the timeout, or, the IO completes, but now I have two callbacks for any single IO operation, the CompletionRoutine, and the WaitOrTimerCallback:</p> <p>if the IO completed, they will be called simutaneously, if the IO is not completed, WaitOrTimerCallback will be called, then I call CancelIoEx, this caused the CompletionRoutine to be called with some ABORTED error, but here is a race condition, maybe the IO will be completed right before I cancel it, then ... blahblah, all in all its quite complicated.</p> <p>Then I realized I dont actually need BindIoCompletionCallback and CompletionRoutine at all, and do everything from the WaitOrTimerCallback, it may work, but here is the interesting question, I wanted to build an IOCP-based Winsock server in the first place, and thought BindIoCompletionCallback is the easiest way to do that, using the threadpool provied by Windows itself, now I endup with a server without IOCP code at all ? is it still IOCP ? or should I forget BindIoCompletionCallback and build my own IOCP threadpool implementation ? why ?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload