C# WSAEWOULDBLOCK处理 我用C++编写了一个服务器的套接字,使用Winsock。套接字使用异步方法发送、接收和接受连接。在生产环境中实现套接字后,send函数停止工作,并给出错误WSAEWOULDBLOCK。根据我在网络上的研究,这意味着套接字IO的网络缓冲区已满,或者网络太忙,此时无法执行我的操作。但是,我没有看到任何具体的解决办法来解决这个问题。我的临时解决方案是围绕WSASend函数创建do-while循环,使线程睡眠X毫秒,然后重试。这导致了比以前的套接字(.NET socket类)高得多的延迟和较大的延迟峰值

C# WSAEWOULDBLOCK处理 我用C++编写了一个服务器的套接字,使用Winsock。套接字使用异步方法发送、接收和接受连接。在生产环境中实现套接字后,send函数停止工作,并给出错误WSAEWOULDBLOCK。根据我在网络上的研究,这意味着套接字IO的网络缓冲区已满,或者网络太忙,此时无法执行我的操作。但是,我没有看到任何具体的解决办法来解决这个问题。我的临时解决方案是围绕WSASend函数创建do-while循环,使线程睡眠X毫秒,然后重试。这导致了比以前的套接字(.NET socket类)高得多的延迟和较大的延迟峰值,c#,c++,winapi,c++-cli,winsock,C#,C++,Winapi,C++ Cli,Winsock,我发送数据的代码如下: void Connectivity::ConnectionInformation::SendData(unsigned char data[], const int length) { if (isClosed || sendError) return; Monitor::Enter(this->syncRoot); try { sendInfo->buf = (char*)data;

我发送数据的代码如下:

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的文档中可以看出,wait-for-data方法也可能陷入此错误。有人找到了解决方法吗?

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

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

  • 同步,阻塞
  • 异步、非阻塞、基于回调
  • 你把两者混为一谈,这使你成为两者中最糟糕的。您创建了一个非阻塞套接字,并以潜在的阻塞方式使用它

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


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

    正如@usr所说,我需要将LPWSAOVERLAPPED或LPWSAOVERLAPPED_COMPLETION_例程设置为一个值,以使操作无阻塞。然而,在测试之后,我发现我不需要一个LPWSAOoverlapped对象来调用完成例程。MSDN中WSASend函数的文档中还提到,如果重叠对象和完成例程为NULL,则套接字将充当阻塞套接字


    谢谢,祝大家圣诞快乐

    您使用的是哪种异步操作?非阻塞套接字或重叠I/O?处理多个并发请求的通用体系结构是什么?单线程/选择/非阻塞套接字?完成程序?事件?似乎您没有使用异步IO。为什么会这样?我以为WSASend方法在默认情况下是异步的。send方法是一个send-and-forget方法,因为我不太关心回调的结果。我正在使用.NET线程池等待接收上的回调并接受连接:WaitHandle ^handle=gcnew ManualResetEvent(false);IntPtr handlePointer=handle->SafeWaitHandle->DangerousGetHandle();WSAEventSelect(监听器,(无效*)手持指针,FD_接受);ThreadPool::unAssferRegisterWaitForSingleObject(句柄,回调,nullptr,-1,true);我如何知道我使用的是非阻塞、重叠IO还是阻塞套接字?请将代码附加到您的问题中。在注释中很难阅读。MSDN有一个例子。这是更容易的,因为它只是.NET(没有C++,C++ CLI)。另一种方法是使用多个线程并进行简单的阻塞I/O(仅在C#中)。我的套接字在90%的发送操作中工作,根据我在网络上所读到的信息,当套接字最初阻塞时,我在所有发送操作中都会出现该错误。表示“此错误是在无法立即完成的非阻塞套接字上的操作返回的,例如,当没有数据排队从套接字读取时recv”我知道我需要重试,我只需要一个事件或一些东西,告诉我何时可以发送数据,正如我在第一篇文章中所解释的。@Martin,正如我所解释的,如果数据可以排入内存中的发送队列,则非阻塞模式下的WSASend可以成功。如果队列已满,则调用失败。你刚才引用的文本对recv说了类似的话(你同意吗?)。;你认为我的建议是坚持(1)还是(2)?目前,您没有按照预期的方式使用套接字。如果你做得对,你就不需要举办活动。你只需要调用WSASend,它永远不会失败。因此,从我看到的情况来看,我需要调用ioctlsocket将套接字设置为异步模式。我是否应该在接受连接后调用此方法,是否应该在其中添加任何其他参数而不是空指针?此外,我希望坚持使用非阻塞/异步套接字。@Martin,根据您的说法,您应该将套接字创建为重叠(这与非阻塞不同!),并将WSASend与重叠结构或完成回调(我建议后者)中的至少一个一起使用。请注意,您不应该等待任何东西-只依赖回调。这将迫使您的代码从内到外转换,以便它是基于回调的。也许你可以切换到同步IO(为什么不能?)。