TCP 可靠 = 不丢、不重、不乱序:靠三次握手建连、滑动窗口流水线、确认重传、流量/拥塞控制、四次挥手断开。
建连要双方确认「我能发、我能收、对方能收」,于是走 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」合并在一个报文里发。
TCP 全双工,两个方向分别关闭,故四次挥手:
客户端 服务器
│ ──── FIN ────→ │ ① 我没数据了,关我→你的方向
│ ←──── ACK ──── │ ② 收到(但你→我的方向还开着)
│ ←──── FIN ──── │ ③ 我也没数据了,关我→你的方向
│ ──── ACK ────→ │ ④ 收到,双方关闭
停等协议(每报文等确认)带宽利用率极低,TCP 用滑动窗口连续发多个报文:
对比:流量控制端到端,防快发送方撑爆慢接收方;拥塞控制全网,防太多数据同时涌入导致拥塞。
| 维度 | 流量控制 | 拥塞控制 |
|---|---|---|
| 针对对象 | 接收方处理能力 | 网络整体承载能力 |
| 依据 | 接收窗口 rwnd(对方首部窗口字段) | 网络拥塞信号(丢包/时延) |
| 作用范围 | 一对主机之间 | 全网,全局问题 |
| 实现 | 滑动窗口按 rwnd 收缩 | 拥塞窗口 cwnd 动态调整 |
实际发送窗口 = min(rwnd, cwnd)。
拥塞窗口 cwnd 分四阶段,由丢包信号(3 个重复 ACK 或超时)触发切换:
| 算法 | cwnd 变化 | 何时退出 |
|---|---|---|
| 慢启动 | 每收到一个 ACK,cwnd +1 MSS(每 RTT 翻倍) | 到达慢启动阈值 ssthresh 或丢包 |
| 拥塞避免 | 每 RTT 线性 +1(加性增) | 发生丢包 |
| 快重传 | 收到 3 个重复 ACK 立即重传,不等超时 | 触发快恢复 |
| 快恢复 | ssthresh=cwnd/2,cwnd=ssthresh,进入拥塞避免 | 重传成功 |
对比:慢启动 + 拥塞避免是「探测容量」(指数探测 + 线性逼近);快重传 + 快恢复是「丢包后优雅降级」,避免每次退回慢启动。