当当前没有接收时,传入数据会发生什么

what happens to incoming data, when there is no wsarecv at the moment

本文关键字:数据 什么      更新时间:2023-10-16

我在windows多线程IOCP服务器上工作。为了避免处理许多挂起的读,我总是在每个连接的套接字上只有一个wsarecv操作。简而言之,我的设计看起来像:

  1. 客户端连接后,wsarecv被发送到已连接的套接字上
  2. wsarecv被执行时,数据被处理,wsasend被发送到同一个套接字
  3. wsasend从步骤2完成(GQCS收到通知),wsarecv再次发布。

这意味着在步骤2和步骤3之间有一小段时间,当没有挂起的wsarecv等待客户端数据时,它可以在任何时间出现。

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

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

如果你正在使用TCP,那么你甚至不必担心何时填满这个缓冲区空间,因为这将导致零窗口,并且发送方将希望停止发送(请参阅这里为什么它可能不会真正停止发送),但即使它不这样做,那么你的堆栈将简单地丢弃后续数据报,TCP最终将重新发送它们。

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

你可以选择总是有至少一个WSARecv()挂在连接上a)发布一个以上的开始和b)发布一个新的作为你做的第一件事当一个完成。这对UDP工作得很好,但对TCP来说,这种方法的问题是,你必须允许多个recv可以"同时"完成,然后你必须确保你的I/O线程一起工作,以保持TCP数据流同步(见这里的问题)。

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