第 4 章 · TCP 可靠传输

TCP 可靠 = 不丢、不重、不乱序:靠三次握手建连、滑动窗口流水线、确认重传、流量/拥塞控制、四次挥手断开。

4.1 三次握手:为什么是三次

建连要双方确认「我能发、我能收、对方能收」,于是走 SYN → SYN+ACK → ACK

客户端                      服务器
  │ ──── SYN, seq=x ────→    │   ① 我请求建连
  │ ←─ SYN+ACK, seq=y, ack=x+1 ─│ ② 我同意,并请求反向建连
  │ ──── ACK, seq=x+1, ack=y+1 →│ ③ 我确认收到
  │        连接建立            │

两次只保证客户端→服务器方向可靠;服务器不知自己的 SYN 是否被收到,也防不住「历史失效 SYN」。第三次 ACK 让服务器确认客户端确实想连。不用四次:服务器把「对客户端的 ACK」和「自己的 SYN」合并在一个报文里发。

4.2 四次挥手与 TIME_WAIT

TCP 全双工,两个方向分别关闭,故四次挥手:

客户端                      服务器
  │ ──── FIN ────→           │   ① 我没数据了,关我→你的方向
  │ ←──── ACK ────           │   ② 收到(但你→我的方向还开着)
  │ ←──── FIN ────           │   ③ 我也没数据了,关我→你的方向
  │ ──── ACK ────→           │   ④ 收到,双方关闭
  • 中间两次可不对称:服务器收到 FIN 后可能还有数据,先 ACK、发完再 FIN。
  • TIME_WAIT:主动关闭方发最后 ACK 后还要等 2MSL(约 60s) 才释放。原因:① 确保最后 ACK 到达(若丢,对方会重发 FIN);② 让旧连接的迟到报文彻底消亡,避免污染复用同一端口的新连接。

4.3 滑动窗口与流水线传输

停等协议(每报文等确认)带宽利用率极低,TCP 用滑动窗口连续发多个报文:

  • 发送窗口 = 已发未确认 + 可立即发送的字节范围;接收窗口 = 接收方能缓存的字节范围。
  • 确认号 ack = 期望收到的下一个字节序号,是累计确认——ack=n 表示 n 之前全部到达。
  • 收到 ACK 后窗口右滑腾空间;用序号保证有序,用超时重传处理丢包。

4.4 流量控制 vs 拥塞控制

对比:流量控制端到端,防快发送方撑爆慢接收方;拥塞控制全网,防太多数据同时涌入导致拥塞。

维度流量控制拥塞控制
针对对象接收方处理能力网络整体承载能力
依据接收窗口 rwnd(对方首部窗口字段)网络拥塞信号(丢包/时延)
作用范围一对主机之间全网,全局问题
实现滑动窗口按 rwnd 收缩拥塞窗口 cwnd 动态调整

实际发送窗口 = min(rwnd, cwnd)

4.5 拥塞控制:四种算法

拥塞窗口 cwnd 分四阶段,由丢包信号(3 个重复 ACK 或超时)触发切换:

算法cwnd 变化何时退出
慢启动每收到一个 ACK,cwnd +1 MSS(每 RTT 翻倍)到达慢启动阈值 ssthresh 或丢包
拥塞避免每 RTT 线性 +1(加性增)发生丢包
快重传收到 3 个重复 ACK 立即重传,不等超时触发快恢复
快恢复ssthresh=cwnd/2,cwnd=ssthresh,进入拥塞避免重传成功
  • 慢启动其实不慢——指数增长;「慢」是相对「一开始就全速」。
  • 丢包处理:超时(严重)→ cwnd 归 1,重新慢启动;3 个重复 ACK(轻微)→ cwnd 减半,进快恢复(TCP Reno)。
  • 组合即 AIMD(加性增、乘性减):正常缓慢加,拥塞果断砍半。

对比:慢启动 + 拥塞避免是「探测容量」(指数探测 + 线性逼近);快重传 + 快恢复是「丢包后优雅降级」,避免每次退回慢启动。