TCP拥塞控制

前言

在TCP/IP协议簇中,传输层的TCP协议以可靠性著称,而拥塞控制是TCP实现高效、稳定数据传输的核心机制。网络拥塞如同公路堵车,若发送方无节制的发送数据,会导致网络链路被占满、数据包延迟/丢失,最终陷入"重传-更拥塞"的恶行循环。本文将从拥塞控制的核心概念入手,层层拆解慢启动、拥塞避免、拥塞发生、快速恢复四大算法,帮助大家彻底掌握TCP拥塞控制的底层逻辑。

一、TCP拥塞控制的概念

1.什么是拥塞控制?

拥塞控制的目标是让发送方的发送速率匹配网络的承载能力,避免"发送方数据量>网络传输能力"的情况发生。TCP通过动态调整拥塞窗口(cwnd) 的大小,控制每次发送的数据包数量,从而适配网络的实时状态。

2.关键窗口:拥塞窗口(cwnd)与慢启动门限(ssthresh)

  • 拥塞窗口(cwnd):发送方维护的状态变量,代表当前网络可承受的最大发送数据量,会随网络拥塞程度动态变化。
  • 慢启动门限(ssthresh):区分"慢启动"和"拥塞避免"阶段的临界值,是拥塞窗口增长模式的切换开关:
    • 当 cwnd < ssthresh :进入慢启动阶段,cwnd指数增长;
    • 当 cwnd ≥ ssthresh :进入拥塞避免阶段,cwnd线性增长。
  • 实际发送窗口:TCP的实际发送数据量由 min(cwnd, rwnd) 决定(rwnd为接收方的接收窗口),拥塞控制主要调整cwnd。

3.如何判断网络拥塞?

TCP通过超时重传和重复ACK两种信号感知拥塞:

  • 超时重传:发送方未在规定时间内收到ACK确认,判定网络发生严重拥塞;
  • 重复ACK:接收方连续收到3个相同的ACK,判定发生数据包丢失(轻度拥塞)。

二、TCP拥塞控制主要为四个算法

TCP拥塞控制的逻辑围绕慢启动、拥塞避免、拥塞发生、快速恢复四个阶段展开,四个算法环环相扣,构成完整的拥塞控制闭环。

1.慢启动:一点一点的提高发送数据包的数量

TCP建立连接后,首先进入慢启动阶段,核心是逐步提升发送速率,避免一次性发送大量数据直接冲垮网络。

核心规则

发送方每收到一个ACK确认,拥塞窗口cwnd就加1(以报文段为单位),cwnd呈指数增长(如1→2→4→8→...)。

阶段切换

当 cwnd 增长到 ssthresh 时,慢启动阶段结束,进入【拥塞避免算法】。

2.拥塞避免:平稳增长的"保守策略"

拥塞避免阶段的核心是放缓cwnd的增长速度,从指数增长转为线性增长,降低网络拥塞的概率。

核心规则

发送方每收到一个ACK确认,cwnd按 1/cwnd 的比例增加(等价于每轮传输结束后cwnd加1),cwnd呈线性增长(例如:当 8 个 ACK 应答确认到来时,每个确认增加 1/8,8 个 ACK 确认 cwnd 一共增加 1,于是这一次能够发送 9 个 MSS 大小的数据,变成了线性增长)。

作用

即使网络暂时无拥塞,也不会无限制提升发送速率,始终保持"试探-平稳"的节奏。

就这么一直增长着后,网络就会慢慢进入了拥塞的状况了,于是就会出现丢包现象,这时就需要对丢失的数据包进行重传。

当触发了重传机制,也就进入了【拥塞发生算法】。

3.拥塞发生

当发送方检测到网络拥塞(超时重传/重复ACK),会立即触发拥塞发生算法,大幅降低cwnd,缓解网络压力。拥塞发生的处理分超时重传和快速重传两种场景:

场景1:超时重传(严重拥塞)

超时重传意味着网络拥塞程度较高,TCP会执行"激进"的调整:

  1. 将 ssthresh 更新为当前cwnd的一半;
  2. 将 cwnd 重置为1(是恢复为 cwnd 初始化值,我这里假定 cwnd 初始化值 1),重新进入慢启动阶段。

这种方式虽能快速降低发送速率,但会导致数据流突然锐减,可能引发网络卡顿。

场景2:快速重传(轻度拥塞)

当接收方发现丢了一个中间包的时候,发送三次前一个包的 ACK,于是发送端就会快速地重传,不必等待超时再重传:

  1. 将 cwnd 减半( cwnd = cwnd/2 );
  2. 将 ssthresh 赋值为减半后的cwnd;
  3. 直接进入快速恢复阶段,无需回到慢启动。

4.快速恢复

快速重传和快速恢复算法一般同时使用,快速恢复算法是认为,你还能收到 3 个重复 ACK 说明网络也不那么糟糕,所以没有必要像 RTO 超时那么强烈。

核心规则

  1. 拥塞窗口 cwnd = ssthresh + 3 ( +3是对已收到的3个重复ACK做补偿);
  2. 重传丢失的数据包;
  3. 如果再收到重复的 ACK,那么 cwnd 增加 1;
  4. 如果收到新数据的 ACK 后,把 cwnd 设置为第一步中的 ssthresh 的值(也就是进入快速恢复之前把cwnd减半后,赋值给ssthresh的那个数值),结束快速恢复,回到拥塞避免阶段。

三、完整流程示例

以 ssthresh = 8 为例:

  1. 慢启动
  • 触发条件:连接建立初期, cwnd < ssthresh 。
  • 窗口变化: cwnd 从1开始指数增长(1→2→4→8),当 cwnd = ssthresh=8 时,慢启动结束,进入拥塞避免。
  1. 拥塞避免
  • 触发条件: cwnd ≥ ssthresh 。
  • 窗口变化: cwnd 线性增长(每次传输轮次+1),即8→9→10→11(修正原10→12的错误,严格遵循线性增长规则)。
  1. 快速重传触发
  • 触发条件:收到3个重复ACK,判定单个数据包丢失(非严重拥塞)。
  • 窗口更新:先将当前 cwnd(11) 减半为 5.5 (TCP中取整为6),再把 ssthresh 更新为6(即 ssthresh = 新cwnd=6 )。
  1. 快速恢复
  • 步骤1:初始化窗口, cwnd = ssthresh + 3 = 6 + 3 = 9 ,立即重传丢失的数据包。
  • 步骤2:若后续再收到重复ACK, cwnd 每次+1(如再收到1个重复ACK, cwnd=10 ,用于补偿接收方已收到的后续数据包)。
  • 步骤3:收到新数据的ACK(确认丢失数据包及后续数据均已接收),将 cwnd 重置为 ssthresh=6 ,快速恢复结束,回到拥塞避免阶段。
  1. 拥塞避免(恢复后)
  • 触发条件:快速恢复完成, cwnd = ssthresh=6 。
  • 窗口变化: cwnd 从6开始再次线性增长(6→7→8→9→...),恢复正常的拥塞避免节奏。

四、总结

TCP拥塞控制是"试探-调整-适配"的动态过程:

  • 慢启动通过指数增长快速试探网络容量;
  • 拥塞避免通过线性增长保持传输稳定性;
  • 拥塞发生通过降低cwnd缓解网络压力;
  • 快速恢复则在轻度拥塞时实现高效回弹。

这四大算法的配合,让TCP在复杂的网络环境中,既能保证传输可靠性,又能最大化利用网络带宽。

相关推荐
Jony_1 小时前
高可用移动网络连接
网络协议
chilix6 小时前
Linux 跨网段路由转发配置
网络协议
JaguarJack8 小时前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo8 小时前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack1 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理2 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
gihigo19982 天前
基于TCP协议实现视频采集与通信
网络协议·tcp/ip·音视频
QQ5110082852 天前
python+springboot+django/flask的校园资料分享系统
spring boot·python·django·flask·node.js·php
WeiXin_DZbishe2 天前
基于django在线音乐数据采集的设计与实现-计算机毕设 附源码 22647
javascript·spring boot·mysql·django·node.js·php·html5
龙仔7252 天前
在麒麟V10服务器安全加固,sshd防暴力破解加固,实现“密码错误3次封IP”的需求
服务器·tcp/ip·安全