当目前没有 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()?