Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Windows 当非块发送返回-1时,WSAGetLastError()从不返回WSAEWOULDBLOCK,为什么?_Windows_Sockets_Winapi_Tcp_Nonblocking - Fatal编程技术网

Windows 当非块发送返回-1时,WSAGetLastError()从不返回WSAEWOULDBLOCK,为什么?

Windows 当非块发送返回-1时,WSAGetLastError()从不返回WSAEWOULDBLOCK,为什么?,windows,sockets,winapi,tcp,nonblocking,Windows,Sockets,Winapi,Tcp,Nonblocking,在Windows中,当非块发送返回-1时,WSAGetLastError返回WSAENOBUFS,而不是WSAEWOULDBLOCK,这与linux不同 如何让WSAGetLastError返回WSAEWOULDBLOCK?这是两种完全不同的错误情况 WSAEWOULDBLOCK表示套接字发送缓冲区已满,在不阻塞调用线程的情况下无法接受更多数据 WSAENOBUFS意味着底层内核缓冲区本身已满,根本无法接受更多数据。这很好地表明您一次向套接字发送的数据太多。在正常情况下,您不应该出现此错误 以下

在Windows中,当非块发送返回-1时,WSAGetLastError返回WSAENOBUFS,而不是WSAEWOULDBLOCK,这与linux不同


如何让WSAGetLastError返回WSAEWOULDBLOCK?

这是两种完全不同的错误情况

WSAEWOULDBLOCK表示套接字发送缓冲区已满,在不阻塞调用线程的情况下无法接受更多数据

WSAENOBUFS意味着底层内核缓冲区本身已满,根本无法接受更多数据。这很好地表明您一次向套接字发送的数据太多。在正常情况下,您不应该出现此错误

以下是来自微软知识库的一条有趣的消息:

为了优化应用层的性能,Winsock将数据缓冲区从应用程序发送调用复制到Winsock内核缓冲区。然后,堆栈使用自己的启发式算法(如Nagle算法)来确定何时实际将数据包放到线路上。您可以使用SO_SNDBUF选项更改分配给套接字的Winsock内核缓冲区的数量,默认情况下为8K。如有必要,Winsock的缓冲区可以大大超过SO_SNDBUF缓冲区大小。在大多数情况下,应用程序中的发送完成仅表示应用程序发送调用中的数据缓冲区已复制到Winsock内核缓冲区,而不表示数据已到达网络介质。唯一的例外是通过将SO_SNDBUF设置为0来禁用Winsock缓冲

Winsock使用以下规则来指示对应用程序的发送完成,具体取决于发送的调用方式,完成通知可以是从阻塞调用返回的函数、向事件发送信号或调用通知函数,等等:

•如果套接字仍在SO_SNDBUF配额内,Winsock将复制应用程序发送的数据,并向应用程序指示发送完成

•如果套接字超出SO_SNDBUF配额,并且堆栈内核缓冲区中只有一个以前缓冲过的发送,Winsock将从应用程序发送复制数据,并向应用程序指示发送完成

•如果套接字超出SO_SNDBUF配额,并且堆栈内核缓冲区中有多个先前缓冲的发送,Winsock将从应用程序发送复制数据。Winsock不会向应用程序指示发送完成,直到堆栈完成足够多的发送,将套接字放回SO_SNDBUF配额内,或者只有一个未完成的发送条件

当您试图发送超出内核物理处理能力的数据时,会报告WSAENOBUFS

WSAENOBUFS 10055 没有可用的缓冲区空间。 无法对套接字执行操作,因为系统缺少足够的缓冲区空间或队列已满


您需要将数据分成更小的块,这样就不会使内核负担过重。理想情况下,为了获得最佳性能,您不应该超过getsockoptSO_SNDBUF-1报告的缓冲区大小。但无论哪种方式,当您遇到WSAEWOULDBLOCK时,您应该在WSAENOBUFS之前遇到WSAEWOULDBLOCK,停止发送数据,直到套接字准备好接收更多数据为止。根据您的代码,可以通过选择报告套接字是可写的,或者通过您从WSAAsyncSelect/WSAEventSelect收到FD_WRITE通知来指示。我一直无法理解这篇文档的头绪,也无法理解他们为什么不提高低得离谱的缓冲区大小,而不是引入所有这些复杂因素。您可以使用setsockoptSO_SNDBUF来提高套接字发送缓冲区的大小,但是您无法控制底层内核的缓冲区大小。@EJP:内核很乐意在下面缓冲千兆字节的数据。我不确定缓冲区大小是这里的问题。@HarryJohnston为什么?您只需要一个大小合适的套接字发送缓冲区。没有人要求内核缓冲更多。但是默认大小是8192,这在20世纪80年代已经太小了,而这些奇怪的启发式方法没有固定缓冲区大小,而是悄悄地出现了。