Question

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?

Was it helpful?

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.

OTHER TIPS

While solutions based on Select or blocking sockets are the correct approach, the reason you're running one core at 100% is due to the behaviour of Sleep:-

Look at the docs for WinAPI sleep():

This function causes a thread to relinquish the remainder of its time slice and become unrunnable for an interval based on the value of dwMilliseconds. The system clock "ticks" at a constant rate. If dwMilliseconds is less than the resolution of the system clock, the thread may sleep for less than the specified length of time.

So, if you're polling, you either need to use a much larger sleep time (maybe 20Ms, which is typically a bit greater than the Windows tick rate), or use a more accurate multimedia timer.

I would recommend using a boost::asio::io_service. We receive about 200MB/s of UDP multicast traffic while maxing out a modern CPU. This includes a full reliability protocol and data dispatch to the application. The bottleneck in profiling is the processing, not the boost::asio receive. Code here

It looks like most of the times your call to recvfrom does not return data. Sleeping 1 ms is not much. You should think about increasing the sleep time (cheap, but not best solution) or, the better solution, think about using an event driven approach. Use select() or Windows API to block until the socket is signalled or some other event you are interested in occurs and then call recvfrom. You might need to redesign your program's main loop for that.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top