当目前没有 wsarecv 时,传入数据会发生啥

Posted

技术标签:

【中文标题】当目前没有 wsarecv 时,传入数据会发生啥【英文标题】:what happens to incoming data, when there is no wsarecv at the moment当目前没有 wsarecv 时,传入数据会发生什么 【发布时间】:2014-03-28 18:51:52 【问题描述】:

我在 Windows 中使用多线程 IOCP 服务器。为了避免处理许多挂起的读取,我在每个连接的套接字上总是只有一个 wsarecv 操作。简而言之,我的设计如下:

    客户端连接后,wsarecv 发布到已连接的套接字上 当wsarecv被执行时,数据被处理并且wsasend被发布到同一个socket上 当步骤 2 中的 wsasend 完成时(GQCS 收到通知),wsarecv 会再次发布。

表示第2步和第3步之间有一点时间,此时没有等待客户端数据的挂起wsarecv,随时可能出现。

是这种情况,我应该担心,或者我可以假设如果数据会在这个特定的时间到达,它将存储在某种内部缓冲区中,并在此时从步骤wsarecv 中取出3张贴?

谢谢帮助。

【问题讨论】:

TCP 还是 UDP?无论哪种情况,它都会被缓冲,在 UDP 的情况下,如果缓冲时间过长(随着更多数据进入),它可能会被丢弃。 @maciekm 考虑将它是 tcp 的信息添加到标题、文本和标签中 您总是可以对每个套接字发出多个重叠的 WSARecv() 操作,以确保一个总是可用的,以便为其缓冲区加载数据。 @Chad 丢弃的是新到达的数据,而不是现有数据。 @Martin 只要您知道在 TCP 连接上有多个挂起的 WSARecv() 操作需要您添加代码以确保读取的正确顺序(假设超过 1 个 I/O 线程正在处理 IOCP)。 【参考方案1】:

只要您没有禁用网络堆栈的缓冲(使用SO_RCVBUF 并将缓冲区大小设置为 0),那么您将在网络堆栈中有一些缓冲区空间,如果您没有WSARecv() 待定。

如果您使用 TCP,那么您甚至不必担心填充此缓冲区空间,因为这会导致零窗口,并且发送方希望停止发送(请参阅 here 了解为什么它实际上可能不会停止发送),但即使不发送,您的堆栈也会简单地丢弃后续数据报,TCP 最终会重新发送它们。

UDP 有点不同。如果你填满了 recv 缓冲区,那么你将开始丢弃数据报。默认情况下,堆栈将丢弃最新的数据报,您可以通过设置 SIO_ENABLE_CIRCULAR_QUEUEING 来更改此设置,这将导致最旧的数据报被丢弃。

您可以选择始终让至少一个WSARecv() 挂起连接,方法是:a)发布多个以开始,b)发布一个新的作为完成后您要做的第一件事。这对 UDP 很有效,但是对于 TCP,这种方法的问题是您必须考虑到多个 recv 可以“同时”完成的事实,然后您必须确保您的 I/O 线程一起工作以保持TCP 数据流同步(有关问题,请参阅here)。

禁用堆栈的 recv 缓冲区并始终有足够的 WSARecv() 挂起连接可能会提高性能,因为这会从入站数据路径中删除内存副本。

【讨论】:

以上是关于当目前没有 wsarecv 时,传入数据会发生啥的主要内容,如果未能解决你的问题,请参考以下文章

当调用winsock 中的recv 函数并且没有收到所有数据时会发生啥?

如何知道完成数据包是针对 WSASend() 还是 WSARecv() 还是 AcceptEx()?

Golang TCP 错误 wsarecv

使用套接字时,哪些 IO 操作会导致完成数据包发送到完成端口?

如果你传入一个无效的 widgetvar 会发生啥?

当我们重新启动 Azure Databricks 群集时,内部会发生啥?