TCP/UDP协议深度解析(三):TCP流量控制的魔法—滑动窗口、拥塞控制与ACK的智慧
🔍 开发者资源导航 🔍 |
---|
🏷️ 博客主页: 个人主页 |
📚 专栏订阅: JavaEE全栈专栏 |
本系列往期内容~
TCP/UDP协议深度解析(一):UDP特性与TCP确认应答以及重传机制
TCP/UDP协议深度解析(二):TCP连接管理全解,三次握手四次挥手的完整流程
前言
在理解了TCP连接管理的基础后,让我们继续探索TCP协议更高阶的流量控制艺术。如果说连接管理是TCP的"骨架",那么流量控制就是它的"神经系统",让数据传输既高效又优雅。
🔍 本期核心内容
- 滑动窗口机制:如何实现"批量发货"的高效传输?
- 流量控制:接收方如何用rwnd窗口温柔地说"慢一点"?
- 拥塞控制:从慢启动到BBR,TCP如何智能适应网络状况?
- 延时应答与捎带应答:TCP协议中的"时间管理"技巧
📌 为什么这些机制至关重要?
- 滑动窗口让TCP告别"单包等待"的低效模式
- 流量控制避免接收方被数据"淹没"
- 拥塞控制是TCP保持网络稳定的关键
- 延时应答与捎带应答让ACK更"智能"
🚀 技术亮点
- 零窗口探测机制:当接收方说"暂停"时会发生什么?
- 快重传与快恢复:TCP如何快速从丢包中恢复?
- 延迟ACK的优化技巧:等待的艺术
一、 滑动窗口
往期中我们讲到过的确认应答、超时重传以及连接管理三个机制保证了连接时的可靠性,但是可靠性带来的代价就是效率的降低,因此为了保证传输的效率引入了滑动窗口机制,对数据进行批量传输。
1.1 传输方式
在滑动窗口的传输模式中,它发送的前几个数据包是不需要等待对方返回ack,可以直接往后发送的,等发送量达到窗口大小后再进行等待,让它用一份时间去等待更多组的ack。
窗口大小:不需要等待,可以直接发送的最大数据量。
🤔那么窗口是如何等待的呢❓
方案1:等待所有的ack都回来,再发第二组。❌效率太慢啦~
方案2:收到一个ack,就发下一条。✅TCP使用的该方案,效率更高、也能保证可靠性。
窗口在收到一条ack后,就往后移动一次,并且发送下一条数据,从宏观上这个窗口就在快速滑动。
滑动窗口越大,批量发的数据就越多,效率就越高,但是窗口也不能无限大否则会影响到可靠性。
1.2 丢包情况的处理
🔎情况1:数据包正常,ack丢失
如果ack部分丢失,但是后续的ack抵达了,那么滑动窗口会直接跳到该ack的位置,因为ack的意义是该序号前面的数据都已经收到了,因此即使前面的ack丢失也可以被后续的覆盖掉。
🔎情况2:数据包丢失
如果数据包产生了丢失,因为确认应答机制,发送方会一直返回丢失的序号,达到三次后就会触发快速重传,进行重发。
快速重传可见本系列第一期:快速传送
二、流量控制
2.1 流量过大会导致的问题
接受方中都会存在一个数据的缓冲区,数据先要保存在缓冲区内,等待接收方的处理,而如果接收方的处理速度太慢并且缓冲区也满了,再次发送数据就会因为没有空间可以存储而被抛弃。
接收方的速度我们没有办法进行控制,但是我们可以根据缓冲区的大小对发送方的发送速度进行调整,而控制的方式就是通过调整窗口大小。
2.2 窗口大小的动态调整
流量控制可以让接收方根据自身处理数据的速度,反馈给发送方限制发送方发生的速度,这个机制依赖于TCP报头的窗口大小属性(这里的窗口大小和上面讲述的不一样)。
16位窗口大小含义:接收方缓冲区的剩余大小,发送方会根据这个数字重新设定发送的滑动窗口大小,该属性会随着ack一起发送回来,不会产生多余的消耗。
2.3 特殊情况的处理
🔎情况1:窗口大小不够用咋办?
我们知道16位空间存储的最大是64k,但是缓冲区的真实情况可能会远比它大,因此设计者在考虑的时候对它进行了可增长的处理,在选项中有一个窗口扩展因子的属性,返回的真实大小=16位窗口大小<<该属性,该操作是一个指数增长的过程,因此不必担心不够用的情况。
🔎情况2:接收方缓冲区已满
当缓冲区满时返回的窗口大小为0,发送方会停止发送,但是如果一直不发就无法触发ack,那么对方什么时候有空它也不知道,因此发送方会每隔一段时间发送一个窗口探测包,
窗口探测包并不会携带业务数据,只是为了触发ack,问问对方现在咋样了。
三、拥塞控制
除了流量对窗口大小存在控制外,在传输过程中的设备中也可能会存在产生流量过大而导致丢包的情况,我们将这些设备看做一个整体,对发送方传输速度进行控制,而这就是拥塞控制。
3.1 控制流程
它的控制方式是一个动态平衡的过程:
- 初始先以一个较慢的发送速度发送。
- 在达到ssthresh值之前先以指数级增长。
- 达到ssthresh值之后线性增长。
- 如果过程中产生丢包现象,则把当前速度的二分之一值设为新的ssthresh,重新设置发送速度,之后线性增长。
- 循环往复....
上述过程可以简单理解为:丢包了就减速,没丢包就提速。通过这个流程可以有效的保证窗口以一个最合适的大小发送。
🤔拥塞控制和流量控制谁说的算呢❓
它们两个并不会冲突,窗口大小最终会取他们两个的最小值,毕竟要是选大的肯定会不分过程丢包~
四、 延时应答
默认情况下,接收方在收到数据报的第一瞬间就返回ack,但是可以通过延时返回ack的方式来提高效率。它允许接收方在ACK前缓冲更多数据,通过通告更大的窗口大小,促使发送方发送更大的报文段,提高网络利用率。
4.1 提高效率原理
在接受方的缓冲区内,如果稍晚一些返回数据,在等待的过程中应用程序会消耗掉部分数据,进而可以返回一个更大的窗口大小,在应用程序能顾处理的限度下,尽可能的增加窗口大小。
虽然不是100%提高效率,还是得看应用程序消耗的快不快,但是从经验上看,还是有一定帮助的。
4.2 捎带应答
基于延时应答,引入捎带应答机制,在返回业务数据的时候顺便将上次的ack也给带回去,该机制可以减少报文数量,缓解网络拥塞以及减少消耗的网络带宽 。
原理1:减少ack报文数量
在收到数据包后,TCP默认不会立即发送ACK,而是等待一段时间(通常200ms),期望在此期间有反向数据(如响应报文)需要发送。若有,则ACK可捎带在这些数据包中,无需单独发送。
原理2:合并多个ack
若接收方在延时窗口内连续收到多个数据包(如乱序到达),只需发送一个累积ACK(确认最高按序到达的序列号),而非对每个包单独确认。
4.3 什么时候进行延时
首先肯定不是所有包都得进行延时的,它在延时上存在两个机制:
- 数量限制:每个n个包就应答一次,数据密集的时候使用。
- 时间限制:超过最大时间就应答一次,数据稀疏的时候使用。
因为确认序号具有覆盖性,因此即使少一些ack也不会影响。