【Network】TCP 的流量控制(Traffic Control) - 滑动窗口(Sliding Window)

Posted by 西维蜀黍 on 2019-05-07, Last Modified on 2021-09-21

利用滑动窗口(Sliding Window)实现流量控制(Traffic Control)

如果发送方把数据发送得过快,接收方可能会来不及接收,这就会造成数据的丢失。所谓**流量控制(Traffic Control)**就是让发送方的发送速率不要太快,要让接收方来得及接收。

利用**滑动窗口(Sliding Window)**机制可以很方便地在TCP连接上实现对发送方的流量控制。

设A向B发送数据。在连接建立时,B告诉了A:“我的接收窗口是 rwnd = 400 ”(这里的 rwnd 表示 receiver window) 。因此,发送方的发送窗口不能超过接收方给出的接收窗口的数值。请注意,TCP的窗口单位是字节,不是报文段。TCP连接建立时的窗口协商过程在下图中没有显示出来。

再设每一个报文段为100字节长,而数据报文段序号的初始值设为1。大写ACK表示首部中的确认位ACK,小写ack表示确认字段的值ack。

从图中可以看出,B进行了三次流量控制。第一次把窗口减少到 rwnd = 300 ,第二次又减到了 rwnd = 100 ,最后减到 rwnd = 0 ,即不允许发送方主机A再发送数据。

这使得发送方A会保持暂停发送数据的状态,直到主机B重新发出一个新的窗口值。B向A发送的三个报文段都设置了 ACK = 1 ,只有在ACK=1时确认号字段才有意义。

TCP为每一个连接设有一个持续计时器(persistence timer)。只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器。若持续计时器设置的时间到期,就发送一个零窗口控测报文段(携1字节的数据),那么收到这个报文段的一方就重新设置持续计时器。

TCP的窗口机制

大家都知道TCP和UDP的区别是,TCP是基于连接的(三次握手),而且TCP数据的传输是可靠的,所谓可靠是指,依托序列号及确认号机制让TCP的传输过程中,只要出现丢包就会重传。

但是TCP的确认机制也让TCP连接双方的数据传输速度变慢,也就是说,一方发送数据需要等待对方的确认才继续发送后续数据。这就体现的窗口机制的作用,所谓窗口,也就是充分利用双方的带宽及缓冲区(Buffer)。举个栗子,发送方不必等待对方的确认,可以连续发送多个数据包给对方,而对方可以暂时把这些数据存放在缓冲区,并给对方一个确认。这样,可以大大增加数据传输的速度。

这样做的问题是一旦当接收方的缓冲区填满或即将填满时,就会产生不堪重负的情况,那么这就需要TCP窗口的实时更新机制

举个栗子,接收方窗口大小设置的是50000,也就是说发送方可以不必等待确认,而一次性发送50000字节的数据,一旦接收方意识到不堪重负的情况,可以发送窗口更新通知告诉发送方,现在的窗口大小是30000,请减少一次性发送数据的字节数。某些极端情况,接收方的Buffer完全填满,这时,会发送ZeroWindowSize通知,让发送方暂时停止数据传输,并等待下一个确认通知。

下面我们来看看抓包中是如何体现窗口的特征的:

红框中的那一行可能会让大家疑惑。为什么会有一个Calculated window size呢?

这张图中我们可以看到,windows size的值是2060,但是Calculated Windows Size的值却是131840,这是怎么回事呢?

事实上,在上图这个数据报对应连接的TCP三次握手中的SYN数据报中(对应下图),在Options区包含一个Window Size Scaling,设计出这个选项是因为如今的带宽已经大规模提升,千兆到桌面也是一件常事儿,因此,65535长度的窗口大小已经显得有些小了,为了突破这个限制,便有了Window Size Scaling选项。

我们就具体来看看TCP Header中的这个Option:TCP Window Size Scaling。

可以看到这个字段的值为6,也就是要将Window Size的值左移六2位,即乘以64,因此,上图中我们看到window size值是2060,但是真正选用的值却是2060 * 64 = 131840。

Reference