Skip to content

05. TCP 传输层状态机与拥塞控制全景 ​

💡 交互图解

本章理论对应的动态微观仿真位于:👉 CS 10 图全屏走查 · FIG 06 状态机 与 FIG 07 滑动窗口与拥塞水流波形

1. 三次握手与状态跃迁全景 ​

为什么必须是三次握手?不能是两次? ​

防历史旧连接死灰复燃: 设想客户端发出的第一个 SYN 在某个网络路由器节点被严重拥堵挂起(超时),客户端放弃并重新发送第二个 SYN 顺利完成通信后关闭了连接。 很久之后,那个在网络中游荡的旧 SYN 突然抵达服务端。若只有两次握手,服务端一收到旧 SYN 就误认为新连接已经建立,分配内存与 socket,并白白傻等客户端发送数据。而三次握手下,客户端收到不对劲的 ACK 时会发出 RST 复位包终结该连接。


2. 四次挥手与 TIME_WAIT 2MSL ​

为什么必须在客户端保留 TIME_WAIT 并等待 2MSL? ​

  1. 保证第四次挥手的 ACK 能可靠到达服务端:若最后的 ACK 丢失,服务端因收不到确认会超时重发第三次挥手的 FIN;处于 TIME_WAIT 状态的客户端能够捕捉到这个重发的 FIN,并再次补发 ACK;
  2. 彻底消灭网络残存报文:一个报文在网络中的最大生存时间为 MSL(Maximum Segment Lifetime,通常为 30s~60s)。2MSL 时间足够让本连接产生的所有方向的游魂报文在互联网中自然消亡,防止老报文串入后续新建立的具有完全相同四元组(源IP/端口、目的IP/端口)的新连接中。

3. 滑动窗口与流量控制(Flow Control) ​

TCP 是以字节为单位的滑动窗口协议。双方各有一个缓冲区:

  • 发送窗口 W=min(rwnd,cwnd):
    • rwnd(Receive Window):由接收方在 TCP 首部告知,防止接收方应用层处理不及时导致缓冲区溢出;
    • cwnd(Congestion Window):由发送方根据网络拥塞程度自适应推演。

4. 拥塞控制四大算法波形(Reno 体系) ​


5. 生产级进阶:TIME_WAIT 端口耗尽与现代 BBR ​

生产灾难:高并发短连接导致端口枯竭 ​

微服务调用如果没有正确使用 HTTP 连接池(每次请求都新建连接并关闭),主动关闭端会在本地累积数万个处于 TIME_WAIT 的 Socket,消耗完操作系统的临时可用端口(Ephemeral Ports 范围通常只有几万个),导致后续请求抛出 Cannot assign requested address!

  • 治理之道:开启客户端 HTTP Keep-Alive;在服务间强制采用 RPC 连接池复用长连接;在 Linux 内核层评估配置 net.ipv4.tcp_tw_reuse = 1。

拥塞控制演进:从 Reno/CUBIC 到 Google BBR ​

传统 Reno 和 CUBIC 遵循“丢包即代表网络拥塞”的假设,在现代长肥管道(BDP 极高的高速跨国公网)或无线弱网中,少量的随机链路误码丢包会导致带宽利用率暴跌。 Google 设计的 BBR(Bottleneck Bandwidth and RTT) 通过实时测量网络传输延迟 RTTmin 与最大瓶颈交付率 BtlBw,直接计算当前网络管道的最佳充盈容量(BDP=BtlBw×RTTmin),在不造成缓冲区排队水浸的前提下跑满物理带宽,弱网吞吐量提升高达数倍至数十倍。

学思并济 · 躬行求索 | Released under MIT License