TCP 协议灵魂问题,巩固你的网路底层基础( 五 )


而流量控制索要做的事情 , 就是在通过接收缓存区的大小 , 控制发送端的发送 。 如果对方的接收缓存区满了 , 就不能再继续发送了 。
要具体理解流量控制 , 首先需要了解滑动窗口的概念 。
TCP滑动窗口
TCP滑动窗口分为两种:发送窗口和接收窗口 。
发送窗口
发送端的滑动窗口结构如下:

TCP 协议灵魂问题,巩固你的网路底层基础
文章图片
其中包含四大部分:
已发送且已确认已发送但未确认未发送但可以发送未发送也不可以发送其中有一些重要的概念 , 我标注在图中:

TCP 协议灵魂问题,巩固你的网路底层基础
文章图片
发送窗口就是图中被框住的范围 。 SND即send,WND即window,UNA即unacknowledged,表示未被确认 , NXT即next,表示下一个发送的位置 。
接收窗口
接收端的窗口结构如下:

TCP 协议灵魂问题,巩固你的网路底层基础
文章图片
REV即receive , NXT表示下一个接收的位置 , WND表示接收窗口大小 。
流量控制过程
这里我们不用太复杂的例子 , 以一个最简单的来回来模拟一下流量控制的过程 , 方便大家理解 。
首先双方三次握手 , 初始化各自的窗口大小 , 均为200个字节 。
假如当前发送端给接收端发送100个字节 , 那么此时对于发送端而言 , SND.NXT当然要右移100个字节 , 也就是说当前的可用窗口减少了100个字节 , 这很好理解 。
现在这100个到达了接收端 , 被放到接收端的缓冲队列中 。 不过此时由于大量负载的原因 , 接收端处理不了这么多字节 , 只能处理40个字节 , 剩下的60个字节被留在了缓冲队列中 。
注意了 , 此时接收端的情况是处理能力不够用啦 , 你发送端给我少发点 , 所以此时接收端的接收窗口应该缩小 , 具体来说 , 缩小60个字节 , 由200个字节变成了140字节 , 因为缓冲队列还有60个字节没被应用拿走 。
因此 , 接收端会在ACK的报文首部带上缩小后的滑动窗口140字节 , 发送端对应地调整发送窗口的大小为140个字节 。
此时对于发送端而言 , 已经发送且确认的部分增加40字节 , 也就是SND.UNA右移40个字节 , 同时发送窗口缩小为140个字节 。
这也就是流量控制的过程 。 尽管回合再多 , 整个控制的过程和原理是一样的 。
010:能不能说说TCP的拥塞控制?
上一节所说的流量控制发生在发送端跟接收端之间 , 并没有考虑到整个网络环境的影响 , 如果说当前网络特别差 , 特别容易丢包 , 那么发送端就应该注意一些了 。 而这 , 也正是拥塞控制需要处理的问题 。
对于拥塞控制来说 , TCP每条连接都需要维护两个核心状态:
拥塞窗口(CongestionWindow , cwnd)慢启动阈值(SlowStartThreshold , ssthresh)涉及到的算法有这几个:
慢启动拥塞避免快速重传和快速恢复接下来 , 我们就来一一拆解这些状态和算法 。 首先 , 从拥塞窗口说起 。
拥塞窗口
拥塞窗口(CongestionWindow , cwnd)是指目前自己还能传输的数据量大小 。
那么之前介绍了接收窗口的概念 , 两者有什么区别呢?
接收窗口(rwnd)是接收端给的限制拥塞窗口(cwnd)是发送端的限制限制谁呢?
限制的是发送窗口的大小 。
有了这两个窗口 , 如何来计算发送窗口?
发送窗口大小=min(rwnd,cwnd)
取两者的较小值 。 而拥塞控制 , 就是来控制cwnd的变化 。
慢启动
刚开始进入传输数据的时候 , 你是不知道现在的网路到底是稳定还是拥堵的 , 如果做的太激进 , 发包太急 , 那么疯狂丢包 , 造成雪崩式的网络灾难 。
因此 , 拥塞控制首先就是要采用一种保守的算法来慢慢地适应整个网路 , 这种算法叫慢启动 。 运作过程如下:
首先 , 三次握手 , 双方宣告自己的接收窗口大小双方初始化自己的拥塞窗口(cwnd)大小在开始传输的一段时间 , 发送端每收到一个ACK , 拥塞窗口大小加1 , 也就是说 , 每经过一个RTT , cwnd翻倍 。 如果说初始窗口为10 , 那么第一轮10个报文传完且发送端收到ACK后 , cwnd变为20 , 第二轮变为40 , 第三轮变为80 , 依次类推 。难道就这么无止境地翻倍下去?当然不可能 。 它的阈值叫做慢启动阈值 , 当cwnd到达这个阈值之后 , 好比踩了下刹车 , 别涨了那么快了 , 老铁 , 先hold住!
在到达阈值后 , 如何来控制cwnd的大小呢?
这就是拥塞避免做的事情了 。
拥塞避免
原来每收到一个ACK , cwnd加1 , 现在到达阈值了 , cwnd只能加这么一点:1/cwnd 。 那你仔细算算 , 一轮RTT下来 , 收到cwnd个ACK,那最后拥塞窗口的大小cwnd总共才增加1 。