WSAEWOULDBLOCK处理

时间:2012-12-23 10:38:36

标签: c# c++ winapi c++-cli winsock

我在使用winsock的C ++ CLI中为服务器编写了一个套接字。套接字使用异步方法来发送,接收和接受连接。在生产环境中实现我的套接字后,send函数停止工作,给出错误WSAEWOULDBLOCK。根据我对网络的研究,这意味着套接字IO的网络缓冲区已满或者网络太忙而无法在此时进行操作。但是,我还没有看到任何可以解决这个问题的具体解决方案。我的临时解决方案是围绕WSASend函数创建一个do-while循环,使线程为X量的MS休眠,然后再试一次。这导致了比前一个套接字(.NET套接字类)和大的延迟峰值更高的延迟。

我发送数据的代码如下:

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);
    }
}

有没有办法使用例如WSAEventSelect方法,以便在我能够发送数据时获得回调?从MSDN上的文档中,等待数据方法也可能陷入此错误。任何人都有解决方案吗?

2 个答案:

答案 0 :(得分:3)

错误代码WSAEWOULDBLOCK表示您尝试在非阻塞套接字上操作,但无法立即完成操作。这不是一个真正的错误 - 这意味着您可以稍后重试或安排异步IO(这不会失败)。但这首先不是你想要的。让我解释一下:

您应该以两种方式之一使用套接字:

  1. 同步,阻止。
  2. 异步,非阻塞,基于回调。
  3. 你正在混合两者,这两者都是最糟糕的。您创建了一个非阻塞套接字并以可能阻塞的方式使用它。

    唉,我没有资格为本机代码套接字提供最佳实践。我建议你阅读所有docs for WSASend,因为它们似乎解释了所有这些。

    现在,为什么这个奇怪的错误代码会存在?这是一种性能优化。您可以推测性地尝试同步发送(这非常快)。只有当它失败时,你应该安排一个异步IO。如果您不需要优化(您不需要),请不要这样做。

答案 1 :(得分:0)

正如@usr所说,我需要将LPWSAOVERLAPPED或LPWSAOVERLAPPED_COMPLETION_ROUTINE设置为一个值,以使操作无阻塞。但是,在测试之后,我发现我需要一个LPWSAOVERLAPPED对象才能调用完成例程。在MSDN上还提到了WSASend函数的文档,如果重叠对象和完成例程为NULL,则套接字将表现为阻塞套接字。

谢谢,祝大家圣诞快乐! :)