【问题标题】:Winsock 200ms delay issueWinsock 200ms 延迟问题
【发布时间】:2012-07-12 08:25:40
【问题描述】:

我发现 WinSock 发送调用可能会延迟 200 毫秒

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

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

问题总结

如果重复发送带有 SO_SNDBUF "0" 选项的小消息(

我的问题: 为什么第一次发送消息延迟 200 毫秒?

因为 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 毫秒,依此类推。

这是错的吗?

【问题讨论】:

  • 为什么将 SO_SNDBUF 设置为零?这是一个非常糟糕的主意。越大越好。如果您不想要 Nagle 算法,只需将其关闭即可。其他不懂的东西不要乱搞。
  • @EJP :我同意你的看法(SO_SNDBUF=0 是个坏主意)。跟进第三方库的性能问题只是出于好奇(这解决了 SO_SNDBUF 不是 0)。

标签: c++ winsock


【解决方案1】:

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

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

【讨论】:

  • 如果发送的消息大于 MTU(1460 字节),即使 SO_SNDBUF=0,也会立即返回。
  • 所以,我认为无论 ACK 是什么,发送函数都会返回。它只取决于添加到发送缓冲区或通过网络发送成功。
  • @heekyu : 如果发送的消息大于 MTU,则 TCP 堆栈使用 2 个或更多段(数据包)发送数据。当数据通过 2 个数据包传输时,对端在最后一个数据包之后发送确认。因此,快速网络的阻塞时间是最小的。使用 wireshark 来监控。
  • @heekyu : 所以如果你增加大于 2 MTU 但小于 4 MTU 的消息,它可能会再次开始阻塞。
【解决方案2】:

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

【讨论】:

    【解决方案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。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • 您的情况可能很顺利,因为您没有关闭发送缓冲区 (SO_SNDBUF "0")
      猜你喜欢
      • 2011-01-14
      • 2018-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-09
      相关资源
      最近更新 更多