一、流量控制

双方在通信的时候,发送方的速率与接收方的速率是不一定相等,如果发送方的发送速率太快,会导致接收方处理不过来,这时候接收方只能把处理不过来的数据存在缓存区里(失序的数据包也会被存放在缓存区里)。
如果缓存区满了发送方还在疯狂着发送数据,接收方只能把收到的数据包丢掉,大量的丢包会极大着浪费网络资源,因此,我们需要控制发送方的发送速率,让接收方与发送方处于一种动态平衡才好。
对发送方发送速率的控制,我们称之为流量控制。

二、流量控制过程概述

接收方每次收到数据包,可以在发送确定报文的时候,同时告诉发送方自己的缓存区还剩余多少是空闲的,我们也把缓存区的剩余大小称之为接收窗口大小。
发送方收到之后,便会调整自己的发送速率,也就是调整自己发送窗口的大小,当发送方收到接收窗口的大小为0时,发送方就会停止发送数据,防止出现大量丢包情况的发生。
TCP 首部中,专门有一个字段用来通知窗口大小。接收主机将自己可以接收的缓冲区大小放入这个字段中通知给发送端。这个字段的值越大,说明网络的吞吐量越高。不过,接收端的这个缓冲区一旦面临数据溢出时,窗口大小的值也会随之被设置为一个更小的值通知给发送端,从而控制数据发送量。也就是说,发送端主机会根据接收端主机的指示,对发送数据的量进行控制。这也就形成了一个完整的TCP 流控制(流量控制)。
image.png
当接收方处理好数据,接受窗口 win > 0 时,接收方发个通知报文去通知发送方,告诉他可以继续发送数据了。当发送方收到窗口大于0的报文时,就继续发送数据。
不过这时候可能会遇到一个问题,假如接收方发送的通知报文,由于某种网络原因,这个报文丢失了,这时候就会引发一个问题:接收方发了通知报文后,继续等待发送方发送数据,而发送方则在等待接收方的通知报文,此时双方会陷入一种僵局。
为了解决这种问题,我们采用了另外一种策略:当发送方收到接受窗口 win = 0 时,这时发送方停止发送报文,并且同时开启一个定时器,每隔一段时间就发个测试报文去询问接收方,打听是否可以继续发送数据了,如果可以,接收方就告诉他此时接受窗口的大小;如果接受窗口大小还是为0,则发送方再次刷新启动定时器。
image.png

三、滑动窗口详细过程

利用滑动窗口机制,就可以很方便的在TCP连接上实现流量控制。
主机AB是因特网上的两个主机,已经建立了TCP连接,A给B发送数据,B对A进行流量控制
image.png
A中待发送数据的字节序号,假设每个报文段可携带100个字节的数据。
image.png
AB建立TCP连接的时候,B告诉A,接收窗口为400,A将发送窗口也设置为400。
image.png
A将报文段封装为TCP报文发送,seq表示TCP报文中的序号字段,data表示数据报文段。
A发送的第三个报文在传输过程中丢失,B对A发送的201号之前的数据进行累计确认,并将接收窗口的值调整为300,也就是对A进行流量控制,ACK表示TCP报文首部的标志位,取值1表示确认报文段,ack表示确认号字段,ack=201表示201之前的数据全部正常接收,rwnd是窗口字段,表示接收窗口大小。
image.png
A收到ACK后,将已经发送的报文段移除,并向前滑动窗口,继续发送窗口内的数据,因为接收窗口调整,发送窗口也会调整。201~300已经发送过,所以发送后面的
image.png
对于201~300的数据,在超时重传的时候继续发送该报文段,但是不能再发送其他数据了
B收到重传的报文后,对A发送的501号之前的数据进行累积确认。
image.png
调整接收窗口的值,这是第二次流量控制,发送方的发送窗口也会跟着调整。
image.png
A将数据发送后,B对数据进行累积确认,并调整接收窗口,A的发送窗口也调整后,变成了0,也就是不能再发送数据了。
image.png
假设一段时间后,B有了一些缓存,重新调整接收窗口,并通知A,但是这个消息丢失了,A在等待继续发送报文的通知,B在等待A的数据,就变成了死锁。
image.png
为了解决这样的问题,TCP为每个连接设置一个持续计时器,只要一方接收到0窗口通知,就启用持续计时器,如果计时器超时,就发送一个0窗口探测报文(仅携带一个字节的数据),对方接收到探测报文后返回接收窗口值,如果窗口值为0,发送探测报文的一方就重新启动计时器,如果窗口不是0,就打破了死锁局面。
image.png
接收窗口为0,如何接收探测报文,又如何返回确认?
TCP协议规定,即使接收窗口为0,也必须接收0窗口探测报文段,确认报文段,以及携带有紧急数据的报文段。
如果0窗口探测报文段丢失,能否打破死锁局面?
0窗口探测报文段,也有重传计时器,当计时器超时,探测报文段重传。
image.png

四、一些术语及其注意点说明

1、这里说明下,由于TCP/IP支持全双工传输,因此通信的双方都拥有两个滑动窗口,一个用于接受数据,称之为接收窗口;一个用于发送数据,称之为拥塞窗口(即发送窗口)。指出接受窗口大小的通知我们称之为窗口通告。
2、接收窗口的大小固定吗?
在早期的TCP协议中,接收窗口的大小确实是固定的,不过随着网络的快速发展,固定大小的窗口太不灵活了,成为TCP性能瓶颈之一,也就是说,在现在的TCP协议中,接受窗口的大小是根据某种算法动态调整的。
3、接受窗口越大越好吗?
接受窗口如果太小的话,显然这是不行的,这会严重浪费链路利用率,增加丢包率。那是否越大越好呢?答否,当接收窗口达到某个值的时候,再增大的话也不怎么会减少丢包率的了,而且还会更加消耗内存。所以接收窗口的大小必须根据网络环境以及发送方的拥塞窗口来动态调整。
4、发送窗口和接收窗口相等吗?
接收方在发送确认报文的时候,会告诉发送方自己的接收窗口大小,而发送方的发送窗口会据此来设置自己的发送窗口,但这并不意味着他们就会相等。首先接收方把确认报文发出去的那一刻,就已经在一边处理堆在自己缓存区的数据了,所以一般情况下接收窗口 >= 发送窗口。

参考链接:https://zhuanlan.zhihu.com/p/409560860
参考链接:https://blog.csdn.net/weixin_45750972/article/details/123536200