先记住这个答案
SACK是TCP头选项中的选择性确认,接收方在ACK中携带SACK块,描述哪些乱序到达的字节区间已缓存。发送方根据SACK与累积ACK推出真实空洞,只重传空洞中的数据。这解决了早期TCP仅靠累积ACK时,多个丢包后发送方无法及时获知所有空洞、可能重传已收到数据或需多轮触发重传的低效问题,显著节省带宽和减少无效发送。扩展D-SACK还能报告重复收到的段,让发送方识别不必要的重传。
- SACK精确报告空洞,只重传丢失段
- D-SACK检测重复传输,避免冗余重传
- SACK需双方协商,不改变拥塞控制
SACK如何精准定位丢失段
传统TCP使用累积ACK,序号N表示N之前所有字节已收到。当多个段丢失时,接收方只能确认到第一个空洞之前,后续乱序数据虽被缓存但无法精确告知发送方,发送方只能通过重复ACK逐触发快速重传或等待超时,恢复过程可能多次往返或出现无效重传。SACK选项使接收方能在确认之外报告已收到的连续区间,让发送方精确掌握哪些段需要补发。
SACK选项位于TCP头,长度可变,可携带最多四个不重叠的块,每个块由一对32位序号表示开始和结束。发送方解析SACK后,对每个空洞只发送缺失的段。D-SACK是SACK的扩展,接收方发送的块描述的是已经收到的重复段,用于让发送方意识到自己重传了不该传的段,从而优化后续重传策略。
高速链路多段丢失场景
假设发送窗口为64KB,段长1500字节,窗口内约43段。若中间四个段丢失(如序号1200、4200、7800、10500),接收方收到后续数据后缓存并产生空洞。没有SACK时,发送方只能通过累积ACK确认最早的未确认序号,后续丢失段需等待额外的重复ACK或超时才能逐个触发重传,恢复需要多个RTT,期间可能因超时重传已收到的数据,造成不必要的拥塞窗口收缩。
启用SACK后,接收方的ACK携带已收到的区间,发送方可以立即识别所有四个空洞,只需重传那四个丢失段,而不必等待多轮重复ACK或超时,恢复时间可压缩到一个RTT左右。这样既减少了无效重传,也加快了吞吐恢复,并降低了因反复快速重传导致的不必要窗口收缩次数。
SACK的局限与依赖条件
SACK要求通信双方在握手时通过TCP选项确认支持。若一端不支持或中间设备剥离选项,SACK会被忽略,退化为传统累积确认。此外,接收方内存不足时可能丢弃已缓存的乱序数据,导致SACK信息不完整,发送方仍可能过度重传。
D-SACK在部分旧实现中可能未启用,且基础SACK最多覆盖4个间隔。当失序块超过4个时,无法精确描述所有空洞,只能依靠累积ACK和定时器兜底。SACK本身不调整拥塞窗口,若同时发生大量真实拥塞,仍需依赖拥塞控制算法避免网络崩溃。
容易答错的地方
- 认为SACK避免所有重传
- SACK只告诉哪些到了,发送方仍可能因超时或错误推断重传不丢的段,例如接收方缓存区满无法缓存乱序数据时,SACK信息缺失,发送方只能按传统方式处理。
- SACK会加重网络负担
- 实际上SACK只增加少量选项字节,却减少大量无效重传数据。在丢包较多的网络中,它降低总体负载,并不替代拥塞控制,而是与之配合。
面试官还会怎么问?
SACK和快速重传的关系是什么?
快速重传依赖重复ACK判断丢包,SACK提供更精确的丢失区间,使快速重传后能够只补空洞而非重传整个窗口。二者结合显著降低冗余传输,快速重传触发条件不变,但重传内容更精准。
D-SACK为什么重要?
D-SACK让发送方知晓自己重传了已到达的段,从而识别虚假超时或快速重传,帮助调整RTO估算和重传策略。例如网络延迟突然增大可能造成伪重传,D-SACK能揭示这一情况,避免重复发送。
TCP SACK选项最多描述几个块?
标准SACK选项用一对32位序号表示一个块,TCP头选项最多40字节,扣除必要字段后通常容纳4个块。当空洞多于4个时,接收方只能报告最早或最重要的块,发送方对未报告区域仍需保守处理。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。