2

在 Windows XP 上,当我在非阻塞套接字上的迭代中调用WSASend时,它会因 WSAENOBUFS 而失败。

我这里有两个案例:

情况1:

在非阻塞套接字上,我正在调用WSASend。这是伪代码:

while(1)
{
    result = WSASend(...); // Buffersize 1024 bytes
    if (result == -1)
    {
        if (WSAGetLastError() == WSAENOBUFS)
        {
            // Wait for some time before calling WSASend again
            Sleep(1000);
        }
    }
}

在这种情况下,WSASend 成功返回大约 88000 次。然后它会因 WSAENOBUFS 而失败,即使在经过一段时间尝试后也不会恢复,如代码所示。

案例二:

为了解决这个问题,我参考了这个并按照那里的建议,就在上面的代码之前,我用 SO_SNDBUF调用了setsockopt并将缓冲区大小设置为 0(零)

在这种情况下,WSASend 成功返回大约 2600 次。然后它失败了。但是在等待它再次成功 2600 次之后,它又失败了。

现在我在这两种情况下都有这些问题:

情况1:

  1. 是什么因素决定了这个数字88000?
  2. 如果失败是因为 TCP 缓冲区已满,为什么一段时间后它没有恢复?

案例二:

  1. 同样,是什么因素决定了这里的数字 2600?
  2. 如 Microsoft 知识库文章中所述,如果它直接从应用程序缓冲区发送内部 TCP 缓冲区而不是内部 TCP 缓冲区,为什么它会因 WSAENOBUFS 而失败?

编辑:

在异步套接字的情况下(在 Windows XP 上),行为更奇怪。如果我忽略 WSAENOBUFS 并继续进一步写入套接字,我最终会断开 WSAECONNRESET。目前不确定为什么会发生这种情况?

4

1 回答 1

5

这些值未记录在案,取决于您的计算机上安装的可能位于您的应用程序和网络驱动程序之间的内容。它们可能与机器中的内存量有关。在 Vista 及更高版本上,限制(很可能是非分页池内存和 i/o 页面锁定限制)可能要高得多。

处理该问题的最佳方法是在您的协议中添加应用程序级别的流量控制,这样您就不会认为您可以以您喜欢的任何速率发送。有关非阻塞和异步 I/O 如何导致资源使用激增以及您如何无法控制它的详细信息,请参阅此博客文章,除非您拥有自己的流控制。

总之,永远不要假设您可以使用非阻塞/异步 API 尽可能快地将数据写入线路。请记住,由于 TCP/IP 的内部流控制的工作原理,您可能会使用无法控制的本地机器资源,而客户端是唯一可以控制这些资源以多快的速度释放回服务器上的 O/S 的东西机器。

于 2013-10-28T14:11:35.093 回答