WSAEWOULDBLOCK handling

放肆的年华 提交于 2020-08-27 21:25:39

问题


I have written a socket for a server in C++ CLI that is using winsock. The sockets are using async methods for sending, receiving and accepting connections. After implementing my socket in the production environment, the send function stops working giving me the error WSAEWOULDBLOCK. Out from my research on the net, this means the network buffer for socket IO is full or the networking is too busy to do my operation at this moment. However, I have not seen any specific solution which can address this problem. My temporary solution was to create a do-while loop around the WSASend function, making the thread sleep for X amount of MS and then try again. This resulted in far higher latency than the previous socket (.NET socket class) and large lag spikes.

My code for sending data is as following:

void Connectivity::ConnectionInformation::SendData(unsigned char data[], const int length)
{
    if (isClosed || sendError)
        return;

    Monitor::Enter(this->syncRoot);

    try
    {
        sendInfo->buf = (char*)data;
        sendInfo->len = length;

        do
        {
            state = 0;
            if (WSASend(connection, sendInfo, 1, bytesSent, 0, NULL, NULL) == SOCKET_ERROR)
            {
                state = WSAGetLastError();
                if (state == WSAEWOULDBLOCK)
                {
                    Thread::Sleep(SleepTime);
                    //Means the networking is busy and we need to wait a bit for data to be sent
                    //Might wanna decrease the value since this could potentially lead to lagg
                }
                else if (state != WSA_IO_PENDING)
                {
                    this->sendError = true;
                    //The send error bool makes sure that the close function doesn't get called
                    //during packet processing which could cause a lot of null reffernce exceptions.
                }
            }
        }
        while (state == WSAEWOULDBLOCK);
    }
    finally
    {
        Monitor::Exit(this->syncRoot);
    }
}

Is there a way to use for example the WSAEventSelect method in order to get a callback when I am able to send data? Out from the documentation on MSDN, the wait for data method could also get stuck in this error. Anyone got any solutions for getting around this?


回答1:


The error code WSAEWOULDBLOCK means that you attempted to operate on a non-blocking socket but the operation could not be completed immediately. This is not a real error - it means that you can retry later or schedule an asynchronous IO (which wouldn't fail). But this is not what you want in the first place. Let me explain:

You are supposed to use sockets in one of two ways:

  1. Synchronous, blocking.
  2. Asynchronous, non-blocking, callback-based.

You are mixing the two which gets you the worst of both. You created a non-blocking socket and use it in a potentially blocking way.

Alas I'm not full qualified to give best-practices for native-code sockets. I suggest you read all of the docs for WSASend because they seem to explain all of this.

Now, why would this strange error code even exist? It is a performance optimization. You can speculatively try to send synchronously (which is very fast). And only if it fails you are supposed to schedule an asynchronous IO. If you don't need that optimization (which you don't) don't do it.




回答2:


As @usr says, I need to have either LPWSAOVERLAPPED or LPWSAOVERLAPPED_COMPLETION_ROUTINE set to a value in order to make the operation non-blocking. However, after testing, I found out I need t have a LPWSAOVERLAPPED object in order to make the completion routine called. It is also mentioned on MSDN on the documentation of the WSASend function that if the overlapped object and the completion routine is NULL, the socket would behave as a blocking socket.

Thanks, and merry xmas everyone! :)



来源:https://stackoverflow.com/questions/14010285/wsaewouldblock-handling

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!