2012-07-12 92 views
3

我发现它可以Winsock的延迟为200ms发送呼叫Winsock的200ms的延迟问题

从MSDN: http://support.microsoft.com/kb/214397/en

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

问题总结

如果重复发送带有SO_SNDBUF“0”选项的小型消息(< MTU), 发送功能块200ms。

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

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

但是测试结果不是期望的。

第一条消息也延迟200ms,为什么?

谢谢你的回答。

添加一些细节

的小消息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. 

所以,我想到的是第一条消息立即发送和第二消息等待第一条消息的ACK为200毫秒,因此上。

这是错误的吗?

+0

你为什么设置SO_SNDBUF为零?这是一个非常糟糕的主意。越大越好。如果你不想要Nagle算法,就把它关掉。不要捣鼓其他你不明白的事情。 – EJP 2012-07-12 10:04:29

+0

@EJP:我同意你(SO_SNDBUF = 0是个坏主意)。这仅仅是追踪第三方库性能问题的好奇心(这个解决方案在SO_SNDBUF不为0的情况下解决)。 – heekyu 2012-07-12 23:59:10

回答

4

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

因此,发件人将被阻止,直到所有的数据被同行确认。 如果网络的RTT很长或发生丢包,可能需要200ms以上的时间。

+0

如果发送的消息大于MTU(1460字节),即使SO_SNDBUF = 0,也会立即返回。 – heekyu 2012-07-12 09:07:28

+0

所以,我认为发送函数返回不管ACK。它只取决于添加发送缓冲区或通过网络成功发送。 – heekyu 2012-07-12 09:09:15

+0

@heekyu:如果发送的消息大于MTU,则TCP堆栈使用2个或更多的段(数据包)发送数据。当数据被2个数据包转发时,对方在最后一个数据包之后发送确认。所以用快速网络来阻止时间是最小的。使用wireshark来监视它。 – SKi 2012-07-12 09:29:35

0

老实说,我不记得第一条消息也延迟了这种行为。我和WinSock一起工作,数据运行顺利。他们可以这样实施,因为这不符合任何标准。这是答案。

+1

由于您没有关闭发送缓冲区('SO_SNDBUF“0”'),所以它可能很顺利。 – MSalters 2012-07-12 08:46:47

3

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

3

Nagle算法背后的想法是优化像这样的例子:

  1. 您的发送内发送1个字节的数据()调用毫秒
  2. 后1与您通话1再次发送()数据
  3. 后1毫秒的字节更再次调用发送()

没有Nagle算法这将导致在3个独立的数据包每一个都具有几个字节的首部和仅1的有效负载的字节。这意味着很多开销。

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

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

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

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