3

我发现 WinSock 发送呼叫可能会延迟 200 毫秒

来自 MSDN: http: //support.microsoft.com/kb/214397/en

Nagle 算法: http : //en.wikipedia.org/wiki/Nagle's_algorithm

问题摘要

如果重复发送带有 SO_SNDBUF "0" 选项的小 msg(< MTU),则发送功能块 200ms。

我的问题:为什么先发送消息延迟200ms?

因为 TCP 在第一次发送调用之前是空闲的,所以我认为必须立即发送第一条消息。

但测试结果并不理想。

第一条消息也延迟了 200 毫秒,为什么?

谢谢你的回答。

添加一些细节

Naggle 算法适用于以下小消息:

1. if wire is idle, send it immediately.
2. if formal message's ACK is not received, wait until ACK & send
3. Window's TCP ack delay mechanism send ack after 200ms.

所以,我期望第一条消息立即发送,第二条消息等待第一条消息的确认 200 毫秒,依此类推。

这是错的吗?

4

4 回答 4

4

通常 TCP 将数据保存在发送缓冲区中,直到它被对等方确认。在您的情况下,没有发送缓冲区(因为 SO_SNDBUF=0)。因此,TCP 会阻止发送方保留数据以供可能的重传。对端的 TCP 堆栈使用“Delayed ack”例程,并在 200ms 延迟后发送确认(或直到收到 2 个没有确认的数据包)。

因此,发送方将被阻止,直到所有数据都被对等方确认。如果网络的RTT较长,或者出现丢包,可能需要200ms以上。

于 2012-07-12T08:58:50.440 回答
3

延迟的全部意义在于查看是否有更多数据可以添加到同一条消息中。没有理由为什么第一条消息应该是该规则的例外。

于 2012-07-12T08:45:48.697 回答
3

Nagle 算法背后的想法是优化这样的情况:

  1. 您在 send() 调用中发送 1 个字节的数据
  2. 1 毫秒后,您再次使用 1 字节数据调用 send()
  3. 再过 1 毫秒后,您再次调用 send()

如果没有 Nagle 算法,它将导致 3 个单独的数据包,每个数据包都有几个字节的标头和只有 1 个字节的有用负载。那将意味着很多开销。

使用 Nagle 算法,相同的 send() 调用序列将只产生 1 个带有一些标头字节和 3 个字节的有效负载的数据包,从而减少开销大小。但是,数据包将在您第一次通话后 200 毫秒发送。

Nagle 算法的想法是在您发送一小块数据之后等待您可能想要发送更多数据。由于系统不知道您未来发送任何内容的计划,它会等待一段合理的时间(200 毫秒),如果没有发送更多内容,它会发送实际数据包,以免延迟太大。

如果您以小块的形式发送数据而不等待回复(例如逐行发送文本文件),该算法将对您的程序有益。这将大大减少通过网络发送的数据包数量和相关开销。

如果您的程序对响应时间敏感并且不需要此优化,您可以通过使用 TCP_NODELAY 参数调用 setsockopt() 来安全地禁用它,甚至可以考虑使用 UDP 而不是 TCP。

于 2012-07-12T10:01:20.007 回答
0

老实说,我不记得第一条消息也被延迟的这种行为。我使用 WinSock 并且数据运行顺利。他们可以这样实现它,因为这不违反任何标准。这就是答案。

于 2012-07-12T08:31:52.640 回答