注:本文基于模型知识整理,建议结合权威教材与 RFC 原文核对细节。
一句话定义
流量控制保护「接收方应用读不过来」(对端问题,用 rwnd 通告),拥塞控制保护「网络链路被挤爆」(网络问题,靠 cwnd 自估);TCP 实际发送窗口取二者较小值,并以慢启动、拥塞避免、快速恢复三段式自适应网络容量。
为什么重要
重传(kp-019)解决「送得到」,拥塞控制解决「送得快而不冲垮网络」:没有它,任何一个贪婪的发送端都能触发网络级雪崩。看懂 cwnd 随时间的演化曲线,才能解释「传输起步慢后提速」「速率周期性抖动」「满格信号却掉速」这类现象,也是 kp-021 窗口与缓冲区调优的理论依据。
前置知识
建议先读 kp-019《TCP 可靠传输:确认、重传与滑动窗口》,掌握确认号、RTO 与快速重传语义;带宽时延积的概念如不熟悉,可结合 kp-002 相关知识点补看。
核心概念
- 流量控制(flow control):针对接收方。接收方在每个 ACK 中通告接收窗口(receive window, rwnd),告诉对端「我还能再收多少」,防止接收缓冲区被应用来不及读走的数据淹没。
- 拥塞控制(congestion control):针对网络。发送方自行维护拥塞窗口(congestion window, cwnd),依据丢包与 ACK 到达情况估计网络可用容量;网络本身并不直接通知它。
- 实际发送窗口 = min(rwnd, cwnd):两条约束谁更紧谁生效。
- 慢启动门限(ssthresh):慢启动与拥塞避免的分界。发生超时时置为当时 cwnd 的一半,相当于对网络容量的经验估计值,并随每次丢包动态下调。
公式与模型
发送窗口 = min(rwnd, cwnd)
慢启动:每收到一个 ACK,cwnd 增加 1 个 MSS,等效每 RTT 翻倍(指数增长)
拥塞避免:每 RTT,cwnd 增加 1 个 MSS(线性增长)
超时:ssthresh = cwnd ÷ 2,cwnd 重回 1 MSS 重新慢启动(教材口径;现代实现初始窗口常用 10 MSS)
快速重传触发快速恢复:ssthresh = cwnd ÷ 2,cwnd 减半后线性增长(AIMD:加法增、乘法减)
吞吐量近似:吞吐量 ≈ 发送窗口 ÷ RTT;窗口上限由带宽时延积(Bandwidth-Delay Product, BDP)决定。
图示
cwnd
^
| AIMD 锯齿区:线性增、丢包减半
| /\ /\ /\
| / \ / \ / \ ← 快速恢复:减半后继续线性增长
| / \ / \ / \
| / \/ \/ ← 冗余ACK丢包点
| / ↑
| / 超时丢包点:cwnd 跌回 1 重新慢启动
| / 慢启动(每 RTT 翻倍)
|/
+--------------------------------→ 时间(单位:RTT)
ssthresh 随每次丢包下调到当时 cwnd 的一半,逐渐逼近真实容量原理与机制
慢启动「慢」在起步值小(从 1 个 MSS 开始),增长其实最快:每 RTT 翻倍,指数式探测可用带宽。越过 ssthresh 后转入拥塞避免:每 RTT 只加 1 个 MSS,线性爬坡逼近极限。丢包事件分两类处理:超时意味着网络可能已严重恶化,动作最保守——ssthresh 取 cwnd 的一半、cwnd 跌回 1 重来;收到 3 个冗余 ACK 触发快速重传时,ACK 还在正常返回,说明只是轻度拥塞,进入快速恢复——cwnd 减半后继续线性增长,避免推倒重来。整体就是 AIMD(Additive Increase Multiplicative Decrease,加法增、乘法减):加得慢、减得狠。
它收敛且公平的直觉:同一瓶颈上占用更多的流更早撞上丢包被乘法削减,占用少者继续加性增长,多条流的锯齿逐渐互相咬合、趋于均分带宽。这套机制的隐含假设是「丢包≈拥塞」:在无线高误码链路上,随机丢包会被误判为拥塞而压制速率,这是经典模型的已知局限。现代算法一句定位:CUBIC 将增长改为以离上次丢包的时间为自变量的三次曲线,高带宽下爬升更快(RFC 8312);BBR 直接估计瓶颈带宽与最小 RTT,主动控制排队而不依赖丢包信号。
实例分析
RTT = 50ms 的链路:初始 cwnd = 10 MSS(现代默认),几个 RTT 内翻过 ssthresh 进入线性区;此后从 16 MSS 爬到 32 MSS 需约 16 个 RTT 即 0.8 秒——这就是「下载开局快、随后变稳」的机理。反例:无线链路因信号干扰出现随机丢包,TCP 误判拥塞把 cwnd 砍半,表现为信号满格、速度却骤降,要等线性爬坡慢慢恢复。再看窗口与吞吐的关系:RTT 200ms 的跨洋链路若窗口只有 64KB,吞吐 ≈ 64KB ÷ 0.2s ≈ 320KB/s,与带宽大小无关——窗口不足时吞吐被钳制在窗口/RTT,呼应 kp-002 的带宽时延积结论:要吃满带宽,窗口必须不小于 BDP。
常见误区
一,「慢启动很慢」:慢启动阶段增长最快(指数级),「慢」指起步窗口小。二,「拥塞控制由路由器执行」:经典 TCP 拥塞控制在发送端实现,网络只通过丢包与时延间接反馈。三,「rwnd 与 cwnd 是一回事」:前者保护对端、由接收方给定,后者保护网络、由发送方自估,动机与方向都不同。四,「丢包一定等于拥塞」:无线误码、中间设备策略性丢包同样触发降窗,是经典算法的误伤场景。五,「窗口越大吞吐一定越高」:超过 BDP 后多余窗口只会堆积在瓶颈路由器的队列里,抬高时延甚至诱发更多丢包。
自测题
- 流量控制与拥塞控制分别保护谁?发送窗口如何合并?
答案要点: 流控保护接收方(对端问题,ACK 通告 rwnd);拥塞控制保护网络(发送方自估 cwnd);发送窗口 = min(rwnd, cwnd)。
- 超时与快速重传后的处置为何不同?
答案要点: 超时提示严重拥塞:ssthresh = cwnd/2,cwnd 重回 1 重新慢启动;快速重传提示轻度拥塞:cwnd 减半进入快速恢复后线性增长。
- AIMD 为什么最终公平且收敛?
答案要点: 占用多者更早丢包被乘法削减,占用少者继续加法增长;反复增减后各流锯齿互相咬合、趋于均分,加性过程保证趋向公平分配点。
- 写出吞吐量与窗口、RTT 的关系,并给出设计约束。
答案要点: 吞吐量 ≈ 窗口 ÷ RTT;要达到链路带宽,窗口须不小于带宽时延积,因此大带宽长 RTT 链路必须配置大窗口与大缓冲。
- BBR 在高随机丢包链路上为什么占优?
答案要点: 它不把丢包当拥塞信号,而是估计瓶颈带宽与最小 RTT、主动控制排队时延,因此不会被随机丢包误导而反复降窗。
延伸阅读
- RFC 5681《TCP Congestion Control》
- RFC 8312《CUBIC for Fast Long-Distance Networks》
- Cardwell 等《BBR: Congestion-Based Congestion Control》(ACM Queue,2016)
- 谢希仁《计算机网络》(第 8 版)TCP 拥塞控制章节