《深入理解 RFC 5681:TCP 拥塞控制》

发布时间:2026/7/6 21:21:06

《深入理解 RFC 5681:TCP 拥塞控制》 “网络是共享的谁也不能太贪婪。”—— TCP 拥塞控制的哲学朋友们好今天我们来啃一份互联网世界的“红绿灯规范”——RFC 5681。如果你写过网络程序、调过 TCP 参数、或者只是好奇为什么你在看视频时网络不会突然崩溃那这篇都值得一读。一、它是什么表格问题答案RFC 编号5681全称TCP Congestion ControlTCP 拥塞控制状态 互联网标准Standards Track发布时间2009 年 9 月距今已有十余年但依然核心废除了谁RFC 2581又废除了 RFC 2001一句话定位给 TCP 装上一个“智能油门”既不浪费带宽也不撑爆网络。 核心要解决三个问题新连接怎么开始发数据—— 答案慢启动Slow Start出现丢包如何应对—— 答案快速重传 快速恢复Fast Retransmit/Fast Recovery空闲太久后怎么恢复—— 答案重启窗口Restart Window二、核心机制四个算法一张流程图 发送端的生命周期------------------ | 连接建立完成 | | cwnd IW | ----------------- | cwnd ssthresh? ┌──── YES ──┴── NO ─────┐ ↓ ↓ ------------------ ------------------ | 慢启动 | | 拥塞避免 | | 每 RTT 翻倍 cwnd | | 每 RTT 1 SMSS | ----------------- ----------------- | | ------ 丢包发生? --------- | ----------------- | 检测到丢包方式 | ---------------- | | | ┌──── ────┐ ↓ ↓ ↓ 3个重复ACK 超时 SACK/ECN | | --------- --------- | 快速重传恢复 | 重置 cwnd1 | cwnd 减半 | 重新慢启动 ------------------ 生活类比高速公路的智能限速想象你在一条高速上开车cwnd拥塞窗口是你能同时在路上跑的“车数”的许可证。慢启动刚上高速每次前车到达目的地收到 ACK你就多放两辆车出去——指数级放行快速试探道路容量。拥塞避免当发现路上车已经不少了cwnd 超过阈值改为每次前车到了才多放一辆——线性增长保守试探。丢包 车祸收到 3 个重复 ACK 相当于“后面连续来的车都报告前面有事故”——立即降速到一半并补发丢失的车。超时 彻底堵死很久没收到任何反馈只能停车cwnd1从头探路。三、三个关键窗口和两个阈值cwnd拥塞窗口TCP 发送端的状态变量限制“已发送但未确认”的数据量。升升降降全看网络脸色。ssthresh慢启动阈值初始时设为极大值通常是最大通告窗口丢包时设为max(FlightSize / 2, 2 × SMSS)决定使用慢启动还是拥塞避免的分水岭FlightSize在途数据“已发出但未收到累计确认”的数据量。注意很多实现错误地用了 cwnd 来计算 ssthresh这是不对的应该用 FlightSize。四、开发者必看5 个最容易踩的坑️ 坑 1初始窗口不是固定的“3 段”很多人背了“初始窗口是 3 段”的口诀但标准明确分三档SMSS 2190 → IW 2 × SMSS 1095 SMSS ≤ 2190 → IW 3 × SMSS SMSS ≤ 1095 → IW 4 × SMSS如果你用了巨型帧SMSS 很大初始窗口可能是2 段而不是 3 段️ 坑 2超时后 ssthresh 不是每次都减半第一次超时ssthresh max(FlightSize / 2, 2 * SMSS) cwnd 1 * SMSS但如果是同一段数据第二次超时ssthresh 保持原值不再减半只有 cwnd 重置到 1实现时要注意区分“同一段的重传”和“新段的超时”。️ 坑 3拥塞避免阶段的 ACK 计数要小心拥塞避免期增加 cwnd 有两种主流方式字节计数法推荐累计确认字节数达到 cwnd 后加 1 SMSS公式法cwnd SMSS * SMSS / cwnd注意整数运算中当cwnd SMSS * SMSS时公式可能返回 0标准要求round up 到 1 字节。️ 坑 4延迟确认的两个“紧箍咒”每两个全尺寸段必须至少发一个 ACKSHOULD等待 ACK 不得超过 500msMUST如果接收方 MSS 很大但发送方实际段很小会导致“延展 ACK”问题——性能可能严重退化。️ 坑 5空闲重启的误区TCP 闲置超过一个 RTO 后发送方的 cwnd 必须“缩水”到RW min(IW, cwnd)但标准特别提醒应该以“上次发送数据”为准而不是“上次接收数据”。否则持久 HTTP 连接中服务器收到请求后可能误以为连接“不是空闲”用过大窗口发送造成突发拥塞。五、协议间的配合关系RFC 5681 不是孤立存在的它依赖于一大套 RFC 家族表格相关 RFC作用RFC 793TCP 基础——序列号、确认号、窗口RFC 1122主机要求——强制要求拥塞控制实现RFC 1191 / 4821路径 MTU 发现——决定 SMSSRFC 2988重传定时器——RTO 计算RFC 3042Limited Transmit——前 2 个 dup ACK 时发新数据RFC 3465Appropriate Byte Counting——增强 cwnd 增长鲁棒性RFC 3390增大初始窗口——本标准的 IW 依据RFC 3517 / 3782高级丢包恢复算法SACK-based / NewReno六、安全考虑破坏者能做什么如果用一句话回答RFC 5681 设计的拥塞控制对整个互联网的稳定性至关重要。攻击者可以通过伪造重复 ACK让发送方膨胀 cwnd或通过ACK 分割攻击ACK Division诱导发送方过快增长窗口。标准给出的防御手段使用 Appropriate Byte CountingRFC 3465即按字节计数而非按段计数来增加窗口这样做可以在一定程度上抵御恶意接收者通过“分拆确认”来欺骗发送方。 一句话记住这个协议RFC 5681 就是 TCP 的“自动驾驶系统”——用慢启动试探路况、用拥塞避免保持稳定、用快速重传及时纠错、用快速恢复避免过度刹车。本文基于 RFC 5681September 2009撰写已考虑最新勘误与配套 RFC。你需要进一步了解某个算法的细节如 NewReno vs SACK 的差异、或 ECN 的配合吗欢迎留言或私信。

相关新闻