传输层协议TCP—滑动窗口(6)

传输控制

      TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。在前面的章节中,我们介绍了 TCP 连接的相关概念,也介绍了 TCP 为什么说是一种面向字节流的协议,也基本介绍了为什么说 TCP 是可靠的协议。但是 TCP 中的“C”——控制(Control),体现在哪里呢?在数据传输的过程中,TCP 又是如何控制的呢?要研究 TCP 中的控制,首先要看 TCP 的上下文,如下图5-82所示:

        

      就例如上图来说,TCP 的控制,就是面向发送者(进水速度)、接收者(出水速度)、发送方缓存(发送侧蓄水池)、接收方缓存(接收侧蓄水池)、网络(带宽、QoS(时延、丢包、抖动))的一个控制协议,它既要保证传输的可靠,也要面对各方面的复杂情况。

1.1 滑动窗口

1.1.1 滑动窗口基本概念

        TCP 引入滑动窗口的最直接的原因是“接收方的缓存是有限的”。在 “5.2.7 TCP 连接的收发空间”,我们介绍过,TCP 发送方的最大允许发送字节数,也就是发送方的发送窗口(SND.WND),是由其接收报文中的 Window 字段(SEG.WND)所决定的,即 SND.WND = SEG.WND。SND.WND 是 TCP 发送空间其中1个概念,如下图所示:

        

        SND.WND 称为滑动窗口。顾名思义,是可以滑动的。也就说滑动窗口是动态变化的,如图5-85所示:

        

       这个矩形在 X轴上的左坐标为 WL(window left)、右坐标为 WR(window right)。结合图5-84,我们知道:WL = SND.NXT、WR - WL = SND.WND。图5-85也指出了 WL 只能向右滑,WR 可以左右滑。实际上 WL 何时向右滑,滑多少,取决于 TCP 所发送的报文;WR 何时滑动(或左或右),滑多少,取决于 TCP 所接收的报文。如下图5-86所示:

        

       图5-86中,(1)T0时刻:WL = 7,WR = 12,WR - WL = SND.WND = 5。(2)在 T1 时刻,TCP 发送方,发送了1个报文,这个报文的数据长度是2个字节,于是我们看到了 WL 向右滑动:WL = 9。但是此时 WR 是不滑动的,因为 TCP 发送方还没有收到 TCP 接收方的指示。也正因为此,我们看到 T1 时刻,其滑动窗口的大小 SND.WND = 3,实际上是变小了。(3)在 T2 时刻,TCP发送方,接收了1个报文(对方的 ACK 报文),在这个报文中,其指示了接收窗口的大小等于6(SEG.WND = 6),于是我们看到:SND.WND = 6,同时也意味着 WR 向右滑动 WR = WL + SND.WND = 9 + 6 = 15。

      图5-86中,T2 时刻的 WR 是大于 T1 时刻的 WR,即 WR2 > WR1,但是在某些场景下也会出现 WR2 < WR1 的情形,如图5-87所示:

      

       上图5-87中,在 T2 时刻,TCP发送方,接收了1个报文(对方的 ACK 报文),在这个报文中,其指示了接收窗口的大小等于2(SEG.WND = 2),于是我们看到:SND.WND = 2,同时也意味着 WR 向右滑动 WR = WL + SND.WND = 9 + 2 = 11。而 WR1 = 12,WR2 = 11,即:WR2 < WR1。这种情形,TCP 称为窗口收缩(shrinking the window)。RFC 793 对待窗口收缩的态度是:强烈不建议,但是也不拒绝。

1.1.2 窗口大小与发送效率

       RFC 793 中所定义的 Window 字段有16个 bits,也就说滑动窗口最大可以为65535(不考虑 RFC 1323 的 TCP Window Scale Option)。那么,滑动窗口的大小,与传输效率有什么关系呢?可以用下面这一张图来说明:

       

       图5-88-上,表达的是一个比较大的滑动窗口(比如1000),此时它发送1个100字节长度的数据,只需1对报文(一来一回)即可,所花费的时间记为 t。图5-88-下,表达的是滑动窗口大小只为1的情形,此时它发送1个100字节长度的数据,则需要100对报文(一来一回)。我们忽略网络拥塞等因素,可以简单理解为它所花费的时间是100t。

       太小的滑动窗口(即使比1大一点),其引发的问题主要有:

  • (1)带来很多不必要的传输延时
  • (2)网络带宽利用率极低,而且还很有可能造成网络拥塞

      也正是鉴于此,TCP 其中有有很关键的一点就是致力于滑动窗口大小(size)的研究。

1.2 糊涂窗口综合症

       对于这种来来回回发送的小包,有一个专有称谓:糊涂窗口综合症(Silly Window Syndrome,SWS)。所谓小包,指的是 TCP 报文中的有效载荷(即数据部分)很小,甚至数据长度只有1个字节。这种情形所引发的问题还是比较大的。

       引发糊涂窗口综合症,有3种情形:或者是发送端、或者是接收端、或者是两者兼而有之。对于发送端来说,它产生数据的速度可能很慢(比如 telnet 程序),此时就会引发糊涂窗口综合症。对于接收端来说,原因也是如此——它处理数据的速度很慢——也会引发糊涂窗口综合症,如下图所述:

       

       如上图,接收方一次处理1个字节,仅仅是一个举例,事实上可以不是1个字节,只要是比较小的字节数即可,就会引发糊涂窗口综合症。如果不做一些特殊的处理,在 TCP 的世界里,糊涂窗口综合症几乎是必然要发生的,

1.2.1 接收方治疗方案

       接收方治疗方案基本可以归类为两种。

  • 第1种是 Clark 方案。Clark 方案可以理解为:立即确认0窗口。当接收缓存比较小时,如果收到对方发送过来的报文,接收方会立即确认,但是 ACK 报文中的 Window 字段会等于0。等到自己的缓存比较大(比如大小达到 MSS(maximum segment size),或者达到最大缓存空间的的一半时),再主动 ACK 接收方,告知自己Window。
  • 第2种方案是延迟确认(Delay ACK)。当接收缓存比较小时,如果收到对方发送过来的报文,接收方会稍微等待一段时间再确认——其基本思路是:在等待的这段时间内,自己会处理更多的报文,从而腾挪出更多的接收缓存,此时再发送 ACK 报文,就可以通告一个比较大的窗口。

      当然,延迟确认的“延迟”时间不能过长,否则会让发送方以为发送超时,进而引发重新发送,这就弄巧成拙了。一般来说这个延迟时间是200 ms 或者500 ms(具体多少,是一个经验值),超过这个时间,接收方必须要给对方回应1个 ACK 报文。

1.2.2 发送方治疗方案

也有两种。第一种叫Nagle 算法,第二种是CORK 算法。

Nagle 算法

        Nagle 算法可以用一句话总结:大包随便发(大于等于 MSS),小包发1个要等到确才能发下1个。Nagle 算法的本质仍然是期望能“休息”或者等待一段时间,以使自己能将多个小包“攒”成1个大包发送。这个等待时间就是接收方 ACK 的时间。可以看到,如果对方 ACK 速度比较快,Nagle 算法仍然无法避免小包发送。

       需要说明的是,对于 FIN 报文,Nagle 算法是不等待的,立即发送,因为它并不想延迟 FIN 报文的发送。这句话的潜台词是:Nagle 算法对于其他报文是有可能造成延时的。另外,那些时延敏感的程序,如果遇到“发送方 Nagle 算法 + 接收方延迟确认”,那是雪上加霜:发送方在等接收方的确认,接收方又在等自己慢慢长大。所以,TCP 提供了一个选项“TCP_NODELAY”来禁用 Nagle 算法。nagle算法用伪码表示,如下:

        

CORK 算法

       CORK 算法可以简单理解为:

  • (1)如果是大包(包大小 >= MSS),马上发送
  • (2)如果是小包,那就等。一直等到多个小包“攒”成1个大包,再发送。

       当然,这种等待也不能无限期等下去,TCP 是设置了一个超时时间(经验值是200 ms),如果超时时间到,即使没有攒成1个大包,也得发送出去。从某种意义上说,CORK 算法攒大包的概率比 Nagle 算法更大一点。如果对方 ACK 报文到达的比较快(小于200 ms),Nagle 算法有可能还没攒成1个大包,但是它就得立刻发出去,但是 CORK 算法则可以多等一会(一直等到200 ms),可以多攒一点数据,再发送出去。

       CORK 算法可能会比 Nagle 算法好一点。但是,事物总有两面性,CORK 算法可能会带来更多的延时。也正是鉴于此,TCP 也提供了一个选项“TCP_CORK”来禁用 CORK 算法。

总结

       小包没有大包发送的效率高,而且还有可能会引发网络的拥塞。但是小包的发送,从某种意义上讲是不可避免的。或者是接收方处理速度慢,或者是发送方总是零星地产生数据,但是这些都不受 TCP 控制。 为了应对这种大量小包发送所引发的糊涂窗口综合症,TCP 从接收方到发送方都提出了各种算法。这些算法的本质,说的文雅一点,就是:聚沙成塔、集腋成裘,如果说的粗俗一点就是:攒数据、憋大招,一堆小包变大包。

       这种憋大招的方法,其缺陷也是很明显的,那就是时延,所以它们的应用场景也是有限的。用户在调用 TCP API 时,必要的时候,需要通过 TCP 选项来禁止这些所谓优化的算法。

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值