c++multithreadingsocketsudpwinsockets

UDP recvfrom thread use too much CPU resources


I am writing a Windows 7 visual c++ server application, which should receive UDP datagrams with 3.6 MB/s. I have a main thread where the recvfrom() receives the data. The socket is a non-blocking socket and has 64kB receive buffer. If no data has been received on the socket the thread executes a sleep(1).

My problem is that the thread uses up almost 50% of my dual-core processor and I have no idea how could I decrease it. Wireshark use only 20% of it, so my main goal is to achieve a similar percentage.

Do you have any ideas?


Solution

  • Rather than polling you could use a select-like approach to wait for either data to arrive at your socket or the client to decide to shutdown:

    First make your socket non-blocking:

    u_long nonBlocking = 0;
    WSAEventSelect(sock, NULL, 0);
    ioctlsocket(sock, FIONBIO, &nonBlocking);
    

    then use WSAWaitForMultipleEvents to wait until either data arrives or you want to cancel the recv:

    int32_t MyRecv(THandle sock, WSAEVENT* recvCancelEvt,
                   uint8_t* buffer, uint32_t bufferBytes)
    {
        int32_t bytesReceived;
        WSAEVENT evt;
        DWORD ret;
        HANDLE handles[2];
    
        event = WSACreateEvent();
        if (NULL == evt) {
            return -1;
        }
        if (0 != WSAEventSelect(handle->iSocket, evt, FD_READ|FD_CLOSE)) {
            WSACloseEvent(evt);
            return -1;
        }
    
        bytesReceived = recv(sock, (char*)buffer, bufferBytes, 0);
        if (SOCKET_ERROR==received && WSAEWOULDBLOCK==WSAGetLastError()) {
            handles[0] = evt;
            handles[1] = *recvCancelEvt;
            ret = WSAWaitForMultipleEvents(2, handles, FALSE, INFINITE, FALSE);
            if (WAIT_OBJECT_0 == ret) {
                bytesReceived = recv(handle->iSocket, (char*)buffer, bufferBytes, 0);
            }
        }
        WSACloseEvent(evt);
        return bytesReceived;
    }
    

    Client code would call WSASetEvent on recvCancelEvt if it wanted to cancel a recv.