在 TCP 的世界里,重传机制是确保数据可靠传输的核心环节。大家可能听说过两种确认方式:
- 累计确认(ACK):接收方只告诉发送方“我已经收到了按序的最后一个字节,下一个期望字节是多少”。
- 选择性确认(SACK):接收方可以告诉发送方“哪些数据块收到了,哪些没收到”,更灵活。
很多人疑惑:既然 SACK 更高效,为什么 TCP 没有直接用 SACK 来替代 ACK 呢?
一. 累计确认简单可靠
累计确认的好处是 逻辑简单:
- 只要维护一个指针(期望的下一个字节序号)。
- 接收方无需记录复杂的“哪些收到了哪些没收到”。
- 实现成本低、协议栈开销小。
这在早期计算机性能有限、网络环境简单的背景下,累计确认几乎是最佳选择。
二. SACK 是对 ACK 的增强,而不是替代
SACK 的引入是为了解决丢包率高、乱序多的环境下,累计确认效率低的问题。
举个例子:
- 如果一个窗口里有 10 个包,只丢了第 3 个。
- 累计确认只能说“我只收到了前 2 个,后面的都别算数”,于是发送方会以为后面的 7 个包也丢了,导致重复重传。
- SACK可以说“第 1-2 个收到了,第 4-10 个也收到了,只差第 3 个”,这样发送方只需重传第 3 个,效率高很多。
但问题在于:
- SACK 需要在 TCP 选项字段里携带额外信息(最多能列举 4 个区间)。
- 如果窗口特别大、乱序严重,SACK 选项可能还不够用。
- 依赖 SACK 的 TCP 栈实现更复杂,对兼容性要求高。
所以,SACK 只是对 ACK 的补充,并不是完全替代。
三. 向后兼容性很关键
TCP 是 1970 /1974年代设计的协议,早期已经有大量设备和系统部署。
- 累计确认是 TCP 的必选功能,所有实现都支持。
- SACK是 RFC 2018 才提出的(1996 年),属于“可选功能”。
如果强行替代 ACK:
- 老系统无法兼容,整个互联网传输就会出问题。
- 协议栈升级成本巨大,运维复杂度也会飙升。
因此,ACK 作为基础功能继续保留,SACK 作为增强机制逐步推广,是务实的折中。
四. 复杂网络环境下,ACK 依然必要
还有一个经常被忽视的点:
- ACK 是 TCP 的最小保障机制,即使 SACK 信息丢失,发送方仍能依赖累计确认恢复数据流。
- 如果完全没有 ACK,只靠 SACK,一旦选项字段丢失或解析失败,连接就会陷入混乱。
换句话说,ACK 是底线,SACK 是锦上添花。
总结
TCP 没有让选择性重传(SACK)取代累计确认(ACK),原因主要有:
- ACK 简单高效,协议栈负担小。
- SACK 是增强补充,不是替代。
- 向后兼容性要求极高,ACK 必须保留。
- ACK 是保障机制,哪怕 SACK 出现异常,也能维持传输。
所以今天的 TCP 实现,基本都是 ACK + SACK 协同工作:
- ACK 提供基础的累计确认。
- SACK 提供更高效的选择性反馈,减少不必要的重传。
总结一句话: SACK 解决的是效率问题,ACK 解决的是生存问题。没有 ACK,TCP 的可靠性根基就没了。