2012-04-23 93 views
4

我想了解接收器窗口如何影响吞吐量较高延迟连接。TCP接收窗口

我有两台机器的简单客户端 - 服务器对应用的,相隔甚远,与两个250毫秒的等待时间RTT的之间的连接。我跑这个测试与Windows(XP,7)和Linux(Ubuntu的10.x的),有相同的结果,所以为了简单起见,我们假设的情况下: 客户端接收数据:WinXP的临 服务器发送数据:Win7的临 同样,延迟是250mSec RTT。

我跑我的TCP测试在不改变客户端上的接收缓冲区大小(默认为8KB),我在电线上看到(使用Wireshark的):

  • 客户端发送ACKS到服务器和TCP数据包包含RWIN = 65K
  • 服务器发送数据,并报告RWIN = 65K

在跟踪我看到3-4的分组的突发(具有1460个字节的有效负载)寻找,随后立即ACK从客户端机器发送到服务器,然后约250毫秒没有然后是从服务器到客户端的新数据包突发。

所以,结论看来,它填补了接收器的窗口,甚至在服务器不发送新数据。为了做更多的测试,我这次也运行了相同的测试,改变客户端机器上的接收器缓冲区大小(在Windows上,更改接收器的缓冲区大小最终影响了机器宣传的RWIN)。我希望在阻塞ACK之前看到大量的数据包......并且至少有更高的吞吐量。

在这种情况下,我设置的recv缓冲区大小100,000,000。从客户端到服务器的数据包现在有一个RWIN = 99,999,744(很好,这很好),但不幸的是,从服务器发送到客户端的数据模式仍然是一样的:短时间爆发,然后等待很长时间。 为了确认我在网络上看到的内容,我还测量了从服务器向客户端发送一大块数据的时间。我没有看到使用大型RWIN或使用默认设置的任何更改。

任何人可以帮助我理解为什么改变RWIN并没有真正影响产量?

几点注意事项: - 服务器作为快速发送数据的8Kb 块中可能使用write() - 正如我以前说过,我看到使用Linux以及类似的效果。更改接收缓冲区大小会影响节点使用的RWIN,但吞吐量保持不变。 - 我分析了数百个数据包之后的跟踪,给予TCP慢启动机制足够的时间来放大CWIN大小。


至于建议,我加入金属线轨迹的一小快照这里

No.  Time  Source    Destination   Protocol Length Info 
    21 2.005080 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=11681 Win=99999744 Len=0 
    22 2.005109 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=19305 Ack=1 Win=65536 Len=1460 
    23 2.005116 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=20765 Ack=1 Win=65536 Len=1460 
    24 2.005121 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=22225 Ack=1 Win=65536 Len=1460 
    25 2.005128 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  946 21500 > 57353 [PSH, ACK] Seq=23685 Ack=1 Win=65536 Len=892 
    26 2.005154 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=14601 Win=99999744 Len=0 
    27 2.007106 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=16385 Win=99999744 Len=0 
    28 2.007398 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=24577 Ack=1 Win=65536 Len=1460 
    29 2.007401 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=26037 Ack=1 Win=65536 Len=1460 
    30 2.007403 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=27497 Ack=1 Win=65536 Len=1460 
    31 2.007404 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=28957 Ack=1 Win=65536 Len=1460 
    32 2.007406 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=30417 Ack=1 Win=65536 Len=1460 
    33 2.007408 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  946 21500 > 57353 [PSH, ACK] Seq=31877 Ack=1 Win=65536 Len=892 
    34 2.007883 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=19305 Win=99999744 Len=0 
    35 2.257143 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=22225 Win=99999744 Len=0 
    36 2.257160 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=24577 Win=99999744 Len=0 
    37 2.257358 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=32769 Ack=1 Win=65536 Len=1460 
    38 2.257362 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=34229 Ack=1 Win=65536 Len=1460 
    39 2.257364 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=35689 Ack=1 Win=65536 Len=1460 
    40 2.257365 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=37149 Ack=1 Win=65536 Len=1460 

正如你看到的,服务器停在包#33发送数据。

客户端在旧分组的分组#34发送ACK(seq = 19305,在分组#20上发送,此处未显示)。 RWIN为100Mb,我希望服务器不要阻塞一段时间。

20-30个数据包后,服务器端的拥塞窗口应该足够大,可以发送比我看到的数据包更多的数据包...... 我假设拥塞窗口最终会长到RWIN ......但即使经过数百个数据包之后,模式也是一样的:数据数据然后被阻塞为250mSec ...

+0

无论是机器无线?你能打印出在服务器/客户端发送的数据包和消息中的顺序号吗?客户端或服务器端可能会有很多噪音导致数据丢失。 – JustinDanielson 2012-04-23 23:44:20

回答

7

我可以从你提供的样品猜测两件事情:

  1. 服务器具有大约15K的发送缓冲区。
  2. 您提供的转储是在服务器端完成的。

对于TCP连接的窗口缩放到一定的大小,发送方的发送缓冲区和接收方的接收缓冲区都必须足够大。

实际使用的窗口是接收方提供/请求的接收窗口的最小值以及发送方OS设置的发送缓冲区大小。

长话短说,您需要在服务器上配置发送缓冲区大小。

为了清楚起见,我们来分析一下你的样本数据包。

服务器发送数据的另一一束:

22 2.005109 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=19305 Ack=1 Win=65536 Len=1460 
23 2.005116 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=20765 Ack=1 Win=65536 Len=1460 
24 2.005121 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=22225 Ack=1 Win=65536 Len=1460 
25 2.005128 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  946 21500 > 57353 [PSH, ACK] Seq=23685 Ack=1 Win=65536 Len=892 

通知的PSH。这是一个标志,表明在任何一跳之间已经发送完整的数据块,请将其发送到另一端。 ( “完整的” 块是在这种情况下,你8KB)

在服务器仍在发送,它获得2个ACKS:

26 2.005154 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=14601 Win=99999744 Len=0 
27 2.007106 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=16385 Win=99999744 Len=0 

请特别注意数字:Ack=14601Ack=16385。这些数字是接收器正在确认的数据包的序列号。 Ack = 14601表示“我收到了14601以后的所有东西”。

请注意,这些都是较旧的数据,不在您提供的样本中。

所以服务器处理这些ACK和继续发送数据:

28 2.007398 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=24577 Ack=1 Win=65536 Len=1460 
29 2.007401 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=26037 Ack=1 Win=65536 Len=1460 
30 2.007403 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=27497 Ack=1 Win=65536 Len=1460 
31 2.007404 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=28957 Ack=1 Win=65536 Len=1460 
32 2.007406 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=30417 Ack=1 Win=65536 Len=1460 
33 2.007408 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  946 21500 > 57353 [PSH, ACK] Seq=31877 Ack=1 Win=65536 Len=892 

在这里,我们有一个完整的数据块:1460 * 5 + 892 = = 8192

然后,发送后0.443毫秒去年包,它就会多一个ACK:

34 2.007883 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=19305 Win=99999744 Len=0 

然后还有的几乎完全250ms的延迟,在此期间,服务器发送任何内容,则接收这些前:

35 2.257143 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=22225 Win=99999744 Len=0 
36 2.257160 CCC.CCC.CCC.CCC  sss.sss.sss.sss  TCP  60  57353 > 21500 [ACK] Seq=1 Ack=24577 Win=99999744 Len=0 

,然后继续发送:

37 2.257358 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=32769 Ack=1 Win=65536 Len=1460 
38 2.257362 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=34229 Ack=1 Win=65536 Len=1460 
39 2.257364 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=35689 Ack=1 Win=65536 Len=1460 
40 2.257365 sss.sss.sss.sss  CCC.CCC.CCC.CCC  TCP  1514 21500 > 57353 [ACK] Seq=37149 Ack=1 Win=65536 Len=1460 

有两个非常有趣的事情在这里看到。
首先,服务器发送多少字节而不等待ACK。 Te last ACK seq否在该延迟为Ack=19305之前收到的服务器,并且该服务器在该点发送的最后一个数据包的seq否为Seq=30417

在那个暂停期间,服务器发送的11112个字节尚未被客户端确认。

其次,服务器在发送一堆数据后立即收到一个ACK,但没有触发它发送更多数据。就好像这个ACK不够好。

在此之前收到的ACK是Ack=16385,给出30417-16385 = 14032个字节,这是由服务器在此时未发送确认的。只有在接收到seq no 24577的ACK后,将该计数减少到30417-24577 = 5840,服务器才开始再次发送。

因此,8k的缓冲区大小与16k的有效窗口大小相比的事实意味着吞吐量实际上有所降低,因为服务器将不会发送8k数据块中的任何数据块,直到所有数据都有空间。

最后,对于那些想知道的,有一个称为窗口缩放的TCP选项,它允许连接的一端声明窗口大小实际上是TCP报头中数字的一个倍数。见RFC 1323。该选项在SYN数据包中传递,因此它们在连接中不可见 - 仅提示窗口缩放有效,因为窗口大小TCP标头小于正在使用的窗口。

+0

Michael,该跟踪的服务器发送缓冲区为8kb(默认窗口大小)。我相信的痕迹是在客户端被捕获的。但你说得对:问题在于限制窗口的_SEND_缓冲区。我刚刚在服务器端运行了一个更大的发送者窗口的新测试,在阻止之前我可以清楚地看到更长的数据突发。 Wireshark中的图形清楚地显示了每次收到ACK时拥塞窗口是如何加倍的。 – fabrizi0 2012-04-24 13:53:53

0

在发送机接收到来自接收机的确认时,发送机已经排入了多少数据发送?由于TCP是基于流的协议,在数据流中没有数据包中断,因此TCP发送方无法知道应该何时发送部分数据包,以及何时应该等待更多数据到达。通常情况下,如果一个TCP实现接收到一个数据包的ACK,它会认为它值得传输,直到传输缓冲区为空,但是如果数据在传输之后排队传输,它可能会等待,直到它发送另一个ACK批量。

+0

相信我,发件人缓冲区始终是满的。我的应用程序尽可能快地写入。这是一个for循环,它连续调用8Kb缓冲区的write()。 – fabrizi0 2012-04-23 23:47:02

0

接收器窗口大小直接影响吞吐量。吞吐量< = RWIN/RTT。

有几件事情也可能会降低吞吐量。报头中的ECN位是否设置为1?你知道任何一方是否有包丢失?这似乎是服务器超时。您可以在客户端打印传入数据包和传出ACK的序列号,并在服务器端打印类似信息。如果接收者的序列号是5,并且它接收到6,7,8,9,它将确认6,7,8,9。但是如果丢失了6个,它将在收到包7,8,9时收到ACK 5。序列号可以显示很多信息。

250ms的暂停看起来像是暂停。

Slow-Start

该算法开始于指数生长期最初与1个或2段的拥塞窗口尺寸(cwnd的),并通过1个大小(SS)每个接收到的ACK增加它。由于接收器通常为每两个段发送一个ACK,所以这种行为有效地使网络每往返一次的窗口大小加倍。这种行为一直持续到拥塞窗口大小(cwnd)达到接收者通告窗口的大小或发生丢失为止。

什么可以发生的是
服务器发送1个分组时,获取1个ACK
服务器发送2个分组时,获取2个的ACK(2,3)
服务器发送4个包,得到4次的ack(4,5- ,6,7)
服务器发送8个数据包,得到4个的ACK(数据包丢弃之前的客户端得到了他们)(8,9,10,11)(超时12)
服务器发送4个包,得到4个的ACK(12,13 ,14,15)
服务器发送5个分组时,获取4个的ACK(16,17,18,19)(超时20)
服务器发送3个数据包时,获取3个的ACK(2 0,21,22)
服务器发送4个包,得到4个的ACK(23,24,25,26)
服务器发送5个分组时,获取4个的ACK(27,28,29,30)(超时31)
服务器继续3,4,5环

+0

贾斯汀。没有丢包。我已经证实了这一点。我将尝试从Wireshark获取可打印的痕迹并将其发布到此处。谢谢!!! – fabrizi0 2012-04-24 00:11:37

+0

ECN位可以由路由器设置。这会降低数据发送的速度。客户端可能发送5个数据包,路由器正在设置ECN位或丢弃数据包。 ECN位是一种通知任何一方网络是否拥塞的方法。 http://en.wikipedia.org/wiki/Explicit_Congestion_Notification – JustinDanielson 2012-04-24 00:16:19

+0

如果这是一个高延迟网络,那么沿途可能会有很多跳跃。接收器窗口可以像中间的瓶颈一样大。但是如果这个瓶颈正在丢失数据包,接收者将永远不会知道他们被发送了。所以它会尽可能多地回复数据包,而服务器会等待接收10个数据包而不是4个数据包。 – JustinDanielson 2012-04-24 00:19:56

1

一旦套接字连接,则不能设置> = 64K的接收缓冲区大小。你必须先做。在服务器的情况下,这意味着在侦听套接字上设置接收缓冲区大小:可接受的套接字从它们接受的套接字继承它。如果你不这样做,那么TCP窗口缩放选项就不能被协商,所以对等端无法告诉对方有关64k以上的大小。