TCP 的交互数据流

一些有关TCP通信量的研究如[Caceres et al. 1991]发现,如果按照分组数量计算,约有一半的 TCP报文段包含成块数据(如 FTP、电子邮件和 Usenet新闻),另一半则包含交互数据(如Telnet和R login)。如果按字节计算,则成块数据与交互数据的比例约为 90%和10%。这是因为成块数据的报文段基本上都是满长度(full-sized)的(通常为 512字节的用户数据),而交互数据则小得多(上述研究表明 Telne t和Rlogin分组中通常约 90%左右的用户数据小于 10个字节)。

很明显, TCP需要同时处理这两类数据,但使用的处理算法则有所不同。

1. 经受时延的确认

通常TCP在接收到数据时并不立即发送ACK;相反,它推迟发送,以便将 ACK与需要沿该方向发送的数据一起发送(有时称这种现象为数据捎带 ACK)。

绝大多数实现采用的时延为 200 ms,也就是说, TCP将以最大200 ms 的时延等待是否有数据一起发送。注意,此处的 200ms 并不是说每当数据到达时便等待 200ms,而是 TCP 每隔 200ms 查看一下。它的时间起点不是相对于数据到达时刻!

也就是说,在TCP接收到数据时,它并不立即发送该数据的ACK,相反,它会等待一段时间,如果 这段时间之内,这一端有数据要发送到对方,那么它将会捎带上要发送的ACK随数据一起发送到对方;如果段时间之内,这一端没有数据要发送到对方,那么到时间时它就只好通过一个单独的报文段发送该ACK了。

例子:在一个 Rlogin连接上键入一个交互命令(“date\n”),Rlogin需要远程系统(服务器)回显我们(客户)键入的字符。
在这里插入图片描述
解释
上面中诸如 “0:1(1)” 的数据格式:开始的序号、一个冒号、隐含的结尾序号及圆括号内的数据字节数。

观察 bsdi 端,发现发送 ACK的实际时间(从0开始)为: 139.9、539.3、940.1、1339.9、1739.9、1940.1和2140.1 ms(在图中用星号标出)。这些时间之间的差是 200 ms的整数倍,这里所发生的情况是因为 TCP使用了一个 200 ms的定时器,该定时器以相对于内核引导的 200 ms固定时间溢出。上面红色方框圈出的表示延迟发送的ACK。

观察svr4为产生所收到的每个字符的回显所使用的时间,则这些时间(圆括号中)分别为 16.5、16.3、16.5、16.4和17.3 ms。由于这个时间小于 200 ms,因此我们在另一端从来没有观察到一
个经受时延的ACK。(如果有一个约为 16 ms等待时间越过了内核的 200 ms时钟滴答的边界,则仍可以看到一个经受时延的 ACK。)


2. Nagle算法

该算法要求一个 TCP连接上最多只能有一个未被确认的未完成的小分组,在该分组的确认到达之前不能发送其他的小分组相反, TCP收集这些少量的分组,并在确认到来时以一个分组的方式发出去。

该算法的优越之处在于它是自适应的:确认到达得越快,数据也就发送得越快。而在希望减少微小分组数目的低速广域网上,则会发送更少的分组。

在上图中可以看到,在以太网上一个字节被发送、确认和回显的平均往返时间约为 16ms。为了产生比这个速度更快的数据,我们每秒(1s=1000ms)键入的字符必须多于 60个。这表明在局域网环境下两个主机之间发送数据时很少使用这个算法。

但是,当往返时间(RTT)增加时,如通过一个广域网,情况就会发生变化。还是使用之前的例子,但是这里经过的是广域网。
在这里插入图片描述

  • 我们首先注意到从slip到 vangogh不存在经受时延的 ACK。这是因为在时延定时器溢出之前总是有数据等待发送。

  • 其次,注意到从左到右待发数据的长度是不同的,分别为: 1、1、2、1、2、2、3、1和3个字节。这是因为客户只有收到前一个数据的确认后才发送已经收集的数据。通过使用 Nagle算法,为发送16个字节的数据客户只需要使用 9个报文段,而不再是 16个,减少了报文段个数

  • 在上图中可以看到存在一个经受时延的 ACK,但该ACK是从服务器到客户的(报文段12),因为它不包含任何数据,因此我们可以假定这是经受时延的 ACK。服务器当时一定非常忙,因此无法在服务器的定时器溢出前及时处理所收到的字符。

  • 报文段14和15看起来似乎是与 Nagle算法相违背的,但我们需要通过检查序号来观察其中的真相。因为确认序号是 54(接上报文段11,催促服务器“发货”),因此报文段 14是报文段 12(经受时延的ACK)中确认的应答。但客户在发送该报文段之前,接收到了来自服务器的报文段13(报文段12中并没有服务器发送的数据,所以不求对方确认),报文段15中包含了对序号为56的报文段13的确认。因此即使我们看到从客户到服务器有两个连续返回的报文段,客户也是遵守了 Nagle算法的。

    我的理解:客户端发送报文段11后,收到服务器的确认(报文段12),所以客户端就可以再次发送数据了,也就是报文段14。但是在客户端发送报文段14之前,服务器终于处理完报文段11发给它的数据了,且因为服务器上次发送的报文段12中并没有包含数据,也并不需要客户端确认,所以服务器可以发送报文段13.

关闭Nagle算法

有时我们也需要关闭 Nagle算法。一个典型的例子是 X窗口系统服务器:小消息(鼠标移动)必须无时延地发送,以便为进行某种操作的交互用户提供实时的反馈。

socket API用户可以使用 TCP_NODELAY 选项来关闭Nagle算法。

猜你喜欢

转载自blog.csdn.net/fcku_88/article/details/88372125