网络原理(15):TCP协议十大核心机制 – 滑动窗口 & 流量控制 & 拥塞控制

观前提醒:

如果你是第一次点击这篇博客,需要你点击这篇博客的链接:
网络原理(12):传输层 – TCP协议的报文格式 & 十大核心机制的博客目录
了解这篇博客的内容之后,再回来看这篇博客。

此处,我们讲到的 “TCP数据报的发送”,例如:发送 ack(应答报文)
一定是要通过 IP协议封装(网络层),数据链路层封装,通过物理层转为光电信号,传输给对端,对端接收到光电信号,也要反着解析一遍(分用)。

关于封装和分用,可以看我的这篇博客:
Java网络初识(4):网络数据通信的基本流程 – 封装
Java网络初识(5):网络数据通信的基本流程 – 分用

1. 滑动窗口

这块内容很多需要介绍,大概有 4000字。
如果在这篇博客一起讲了,整体博客的字数就会达到 8300 字。

为了减轻一篇博客的阅读量,我将 滑动窗口 机制的介绍,放在了这篇博客当中:
TCP协议十大核心机制:滑动窗口

推荐点击链接,看完 滑动窗口 机制的博客,再回来看这篇博客。

2. 流量控制(站在接收方考虑)

我们学习了 滑动窗口 之后,会知道:
窗口越大,批量发送的数据越多,效率就越高。
但是,窗口也不能太大,太大也会影响到可靠性。

为什么窗口不能太大,太大也会影响到可靠性?
答:接收方的处理能力,是有上限的!
滑动窗口,是在接收方能够处理一定量的数据的基础上,进行批量数据传输的。

接收方的处理能力,和程序员在应用层写的代码,是有关系的。

2.1 流量控制的作用

这个就好比于小学的一道经典题目:蓄水池,边进水,边放水,问:多久能把这个蓄水池,装满?
在这里插入图片描述
应用程序的读取速度,也就是 接收方 的处理能力,是取决于代码是怎么写的了。

如果,进水速度 > 放水速度,接收缓冲区放不下了,就会 丢包!
如果,进水速度 < 放水速度,发送方会适当增加 窗口大小(批量传输的最大数据量)

通过上述讨论,我们得知:
发送方发送数据,不能发送的那么快(同一时间内,批量传输的数据量),否则,接收方处理不过来,就会发生 丢包。

那么,我们的 “流量控制” ,就是让发送方,踩一下刹车,让发送方发送的速度慢一点。

流量控制,可以让接收方,根据自身处理数据的速度,反馈给发送方,限制发送方发送的速度。

2.2 流量控制是如何工作的

流量控制,如何反馈,反馈什么给发送方,让它能够发送的满一点呢?

我们就需要在 ack 中,依赖一个特殊的属性,叫做:“窗口大小”。
我们回顾一下,TCP的报文:
在这里插入图片描述

报文中,就有一个 “16位窗口大小” ,滑动窗口(批量传输数据) 的过程中,返回的 ack,就会带上这个 “16位窗口大小”。

这个 “16位窗口大小” 的数值是:
接收方接收缓冲区的剩余空间大小。
在这里插入图片描述
ack返回给发送方,发送方就会按照 “16位窗口大小” 的数值,来重新设定发送的滑动窗口大小。
所以,滑动窗口的大小,是动态调整的。

如果 “16位窗口大小” 的数值够大,说明接收方接收缓冲区的剩余空间,还很多,发送方,可以发送更多的数据量。
如果 “16位窗口大小” 的数值比较小,说明接收方接收缓冲区的剩余空间,很少,发送方,需要减少发送的数据量。

“16位窗口大小” 的长度

在介绍 UDP 的报文中:
网络原理(11):传输层 – UDP协议的报文格式
我们说到:
一个bit位,表示一个寻址逻辑地址位数。
一个逻辑地址位数对应一个bit位。
一个逻辑地址位数,有两个取值方式(0 或 1)。
16 个bit位,有 16个逻辑地址位数,有 2^16(2的16次方)种结果
一个端口号的取值范围:0 --> 2^16(2的16次方)

整个 UDP 数据包的长度(UDP报头 + 完整的应用层数据包)
长度属性,是 2个字节 ,16 个bit位。
表示范围:0 - 65535
换算一下,最大为 64KB。
也就说,一个 UDP数据包,最大的长度为 64KB

我们看到 “16位窗口大小”,是否说明:滑动窗口大小,最大数值就是 64KB 呢?
答:不是!

TCP的设计,是后于 UDP 的,TCP的选项里面,有一个窗口扩展因子。
实际窗口大小: “16位窗口大小” <<(左移) 窗口扩展因子

左移操作:是对于一个数字的二进位,进行操作的。
左移一位,相当于原来数字的 2倍。
即:2 << 2 = 8(2 * 4 = 8)

假如,我们此处的窗口大小为 64KB,窗口扩展因子为 2 。
实际窗口大小:64KB << 2 = 256KB
“16位窗口大小” 结合 窗口扩展因子,就能避免最大长度为 64KB 的问题。

问题:流量控制的窗口大小 VS 滑动窗口的窗口大小

那么,ack 依赖的这个 窗口大小,和 滑动窗口 中的窗口大小,是同一个意思吗?或者说,有什么区别?
答:其实,可以认为是一个东西。

滑动窗口中的 窗口大小,其实是没有结合流量控制这个机制,说的一个固定大小。
流量控制这里说的窗口大小,其实是一个动态调整的窗口大小,通过 ack 返回给发送方,发送方,就会根据这个 窗口大小,动态调整自己发送的数据量的多少。
所以说:流量控制,其实是对 滑动窗口 中的窗口大小,重新进行设定,让传输数据的量,能够动态调整。
所以,这两个窗口大小,其实是一个东西。

2.3 图解 流量控制工作流程

我们可以用这样一张图,来表示 流量控制 的工作流程。
在这里插入图片描述
在这里插入图片描述
这张图的工作流程,如下:

  1. 假设此处,应用程序没有读取任何数据
  2. 接收缓冲区满了
    如果发送方继续发送数据包,就会造成 丢包
  3. 发送方发现,目前的窗口大小为0,就会暂停发送
  4. 目前,主机B,已经没有 ack 可以返回了,也就是没有窗口大小的信息可以返回给 主机A 了

如果主机A,一直不发送数据,就没有办法触发 ack 的返回,无法知道主机B的接收缓冲区,是否有空余
此时,主机A 每隔一段时间,就会发送一个窗口探测包(只是为了触发 ack 的返回),询问接收方,是否有空余空间。

如果接收方返回的 ack 中,窗口大小不是 0 了,就说明,接收方的接收缓冲区,有剩余空间。
发送方(主机A),就会根据返回的 窗口大小,发送适量的数据给接收方(主机B)。

2.4 流量控制总结:

流量控制,是结合 滑动窗口 来一起工作的。

发送方,通过滑动窗口机制,批量发送数据给 接收方。
接收方的处理能力,并不是无穷无尽的,是有上限的。

此时,接收方返回给发送方的 ack 中,就会携带一个 窗口大小 的信息。
这个窗口大小,会重新设置 滑动窗口机制 中,窗口大小的值(批量发送的数据量)。
发送方会动态调整发送的数据量,让接收方能够处理尽量多的数据,不至于接收方的接收缓冲区满了,造成丢包。

流量控制,可以让接收方,根据自身处理数据的速度,反馈给发送方,限制发送方发送的数据量。

3. 拥塞控制(站在传输链路来考虑)

流量控制,是依据接收方的处理能力,限制发送方发送的数据量。

流量控制,限制的是发送者。
拥塞控制,限制的是传输路径。

3.1 拥塞控制的作用

拥塞控制,是依据传输链路的转发能力,进行限制的。

我们需要知道:
网络上,任意两台设备,进行网络通信,并不是通过一根网线连起来的。
网络通信的路径上,会有很多的路由器和交换机,数据需要通过许许多多的路由器和交换机,才会到达对方的网络设备。
在这里插入图片描述
接收方,处理能力有限。

那么,传输路径上的这些路由器和交换机,无时无刻,都在传输大量的数据,他们的处理能力,也是会有上限的
数据太多,传输不过来,就会丢包。

传输路径上,传输速度的标准,依照木桶原理。
哪个路由器的速度最慢,我们就以它的速度,来限制发送方的传输速度。

3.2 拥塞控制是如何工作的

流量控制,是根据接收方的接收缓冲区的剩余大小来定量控制发送方。

那么,拥塞控制,根据什么来定量控制发送方?
传输路径上的路由器和交换机,有很多,充满了变数,不同时间,各个设备的状态,是不一样的。
很难根据某一台设备,来定量控制发送方的发送速度啊,怎么办?

我们可以把这一堆的路由器和交换机,视为一个整体,通过 “做实验” 的方式,找到一个合适的窗口大小。
换一句话来说:面多加水,水多加面

发送方会先按照 比较小的窗口(小的速度),先发送数据给接收方。
如果发送的时候,很顺利,不丢包,就会加大窗口(加快速度),一直加,一直加……
如果某一次,发送的过程中,丢包了,就会减小窗口大小(减小速度)
之后,没有丢包了,就会再次加快速度,不丢包,一直加,又丢包之后,就减小窗口大小
……

按照上述这个过程,发送方的数据传输速度,就会达到一个动态平衡。

这就是 “拥塞控制” 的核心思想,以及工作方式。

3.3 流量控制 VS 拥塞控制

流量控制,拥塞控制,这两个机制,都能够限制发送方的窗口大小(传输速度),那么,这两个值,谁说了算?
答:哪个值小,哪个说了算。

数据链路的传输能力 和 接收方处理数据的能力(读取数据的速度),哪个更小,就以哪个为标准。
另外一个,肯定是能够处理得过来的。

3.4 图解 拥塞控制的工作流程

我们可以用这样一张图,来表示 拥塞控制 的工作流程。
在这里插入图片描述
这是一个 传输轮次 - 拥塞窗口 的关系图。
拥塞窗口:拥塞控制机制,计算出来的窗口大小。

在这里插入图片描述

发生丢包之后,ssthtesh的值,发生变化,变为:发生丢包的 拥塞窗口值/2 。

丢包之后,需要减小窗口大小,此时图中,有两种方案:
第一种:直接减小为 第一次 的小窗口
第二种:减小到发生丢包的 拥塞窗口值/2 的值

第一种方案,截止至2025年,已经丢弃了。
我们使用第二种方案。

窗口大小,减小到 新的ssthtesh的值,线性增长 窗口大小。
这种方案,既能减小窗口大小,也能按照一个比较快的速度,传输速度。

上面这张图,一定要重点记住,重点理解,我们以后面试中,被问到 拥塞控制 的工作流程:
慢启动 --> 指数增长 --> 线性增长 --> 丢包,窗口变成较小值

举例理解(谈恋爱):

上面这张图,还是有点难理解的,但是,如果你谈过对象,结合一下,就还是挺好理解的。

谈恋爱流程:
最开始,彼此之间比较害羞(慢启动)
之后,你们的感情可能会因为某个契机,快速升温,达到一个热恋期(指数增长)
热恋期之后,新鲜感逐渐消失,感情趋于平缓(线性增长)
恋爱期间,难免会发生矛盾,吵架,可能会导致分手(丢包)
分手之后,两个人如同陌生人一样(回到慢启动)
之后,双方冷静下来,各自反省,互相道歉,复合(新的指数增长过程)
复合之后,出现新的热恋期,由于之前已经相互熟悉过了,新的热恋期可能会比较短(新的 ssthresh值,降低了)
感情又平稳下来,只不过,这次的平稳期,会比较长(线性增长)
又发生矛盾,但是,不会闹到分手,只是开始冷战了(丢包,窗口变成较小值)
……
之后,就是重复上述过程,最后,走向婚姻殿堂……
在这里插入图片描述
之后,就是重复上述过程,最后,走向婚姻殿堂,生活归于平淡……
所以,所谓爱情,不是风花雪月,而是柴米油盐。

3.5 拥塞控制总结:

拥塞控制,是依据传输链路的转发能力,进行限制的。
传输路径上,传输速度的标准,依照木桶原理。
哪个路由器的速度最慢,我们就以它的速度,来限制发送方的传输速度。

流量控制,是站在 接收方 去考虑的。
拥塞控制,是站在 传输链路 去考虑的。

数据链路的传输能力 和 接收方处理数据的能力(读取数据的速度),哪个更小,就以哪个为标准。

4. 总结:

这篇博客,我们主要学习了 TCP十大核心机制 中的三个:

  1. 滑动窗口
  2. 流量控制
  3. 拥塞控制

其中,滑动窗口,是在 可靠性 的基础上,提高效率的,是在亡羊补牢。
流量控制,是站在 接收方 的角度,考虑接收方的数据处理能力,根据接收方的反馈,对发送方根据 滑动窗口 发送的速度进行限制的。
拥塞控制,是站在 传输链路 的角度,考虑传输链路的转发能力,动态调整 窗口大小,使发送方的数据传输速度,达到一个动态平衡。

你可以理解为:
滑动窗口,是在 可靠性 的基础上,提高效率的
流量控制,拥塞控制,是在限制 滑动窗口,不要让发送方,发送数据的速度太快。

TCP协议的十大核心机制,我们在这篇博客中,会放博客链接,你点击进去这篇博客:
网络原理(12):传输层 – TCP协议的报文格式 & 十大核心机制的博客目录
就可以看到了。

最后,如果这篇博客能帮到你的,请你点点赞,有写错了,写的不好的,欢迎评论指出,谢谢!

更多推荐