TCP的SACK与乱序报文段的处理机制详解
字数 2466 2025-12-14 14:23:48
TCP的SACK与乱序报文段的处理机制详解
一、知识点描述
在标准的TCP确认机制中,接收方只能通过累计确认(ACK)向发送方确认最后一个按序到达的字节。如果网络中发生报文段乱序(Out-of-Order),即使接收方已经收到了后续的一些报文段,发送方也必须等待缺失的报文段重传,这可能导致不必要的性能下降。
选择性确认(SACK, Selective Acknowledgment) 是一种TCP选项,允许接收方明确告知发送方哪些不连续的报文段已经成功接收,从而让发送方只重传真正缺失的部分,而不是盲目重传所有未确认的数据。这对于处理乱序和多重丢包场景至关重要。
二、核心背景知识回顾
-
累计确认的缺陷:
- 接收方只能ACK“期待接收的下一个字节序号”。
- 如果报文段4、5、6乱序到达(比如顺序是5、6、4),即使5和6到达了,接收方仍会一直发送ACK=4(表示期待4),直到4到达。
- 发送方看到重复的ACK=4,可能触发快速重传,但实际只需重传4即可。
-
SACK的基本概念:
- SACK是TCP头部的一个选项(Kind=5),用于携带“已接收的不连续数据块”信息。
- 每个SACK块包含两个序号:[左边界, 右边界),表示一个已成功接收的连续数据范围(左闭右开)。
- 一个ACK报文最多可携带3个SACK块(受TCP选项长度限制)。
三、SACK选项格式与工作机制详解
1. SACK选项格式
Kind=5 | Length | Left Edge of 1st Block | Right Edge of 1st Block | Left Edge of 2nd Block | ...
- Kind:固定为5。
- Length:选项总字节数(包括Kind和Length本身)。
- 每个SACK块包含两个32位序号:左边界(包含)、右边界(不包含)。例如块[1000, 2000)表示字节1000~1999已接收。
2. 接收方的SACK生成逻辑
当接收方收到乱序报文段时:
- 维护一个“已接收但不连续的数据块列表”。
- 在发送ACK时,除了携带标准的ACK序号(累计确认点),还附带SACK块,描述已接收的不连续数据。
- 示例:
- 发送方发送序号:1-1000、1001-2000、2001-3000、3001-4000。
- 接收方收到:1-1000、2001-3000、1001-2000(乱序)。
- 接收方先发送ACK=1001(期待1001),无SACK。
- 收到2001-3000时,发送ACK=1001,SACK块=[2001,3000)。
- 收到1001-2000时,发送ACK=3001(累计确认点前进到3001),此时不再需要SACK。
3. 发送方的SACK处理逻辑
发送方维护一个“SACK接收缓存”,用于记录接收方已确认的不连续数据块:
- 当收到SACK时,更新对应数据块的“已确认”状态。
- 结合快速重传机制:当收到3个重复ACK(且SACK指示了新的数据块),发送方可以推断出哪些数据真正丢失,而不是简单地重传所有未确认数据。
- 核心算法:基于SACK的重传决策。
- 发送方将未确认的数据分为两类:“已知接收方已确认的(通过SACK)”和“可能丢失的”。
- 只重传那些既未被累计确认、也未被SACK块覆盖的数据段。
四、SACK处理乱序的详细示例
假设发送方发送5个报文段,每个1000字节:
Seq=1:1000
Seq=1001:2000
Seq=2001:3000
Seq=3001:4000
Seq=4001:5000
场景:网络乱序,到达顺序为:1、2001、3001、1001、4001。
步骤分解:
-
接收方收到Seq=1:1000:
- 发送ACK=1001(期待1001),无SACK。
-
收到Seq=2001:3000(乱序):
- 期待的还是1001,但已收到2001-3000。
- 发送ACK=1001,SACK块=[2001,3000)。
-
收到Seq=3001:4000(继续乱序):
- 此时已有两个不连续块:2001-3000、3001-4000,可合并为[2001,4000)。
- 发送ACK=1001,SACK块=[2001,4000)。
-
收到Seq=1001:2000(期待的报文到达):
- 此时从1001到4000的数据全部连续。
- 发送ACK=4001(累计确认点跳到4001),SACK可省略。
-
收到Seq=4001:5000:
- 发送ACK=5001。
关键点:接收方通过SACK让发送方知道“2001-4000已收到”,发送方即使看到重复ACK=1001,也不会重传2001-4000,只需考虑重传1001-2000(如果判断丢失)。
五、SACK与快速重传/快速恢复的协同
- 触发快速重传:当发送方收到3个重复ACK(ACK=1001),且SACK块显示有新的数据块到达,发送方推断报文段1001-2000可能丢失。
- 选择性重传:发送方检查未确认的数据段,只重传未被SACK覆盖的段落(即1001-2000)。
- 拥塞控制调整:
- 执行快速恢复,拥塞窗口(cwnd)减半,并进入快速恢复阶段。
- 每收到一个重复ACK(带有SACK),表示有数据离开网络,cwnd可适当增加,允许发送新数据。
六、SACK的局限性与注意事项
-
SACK块数量限制:
- TCP选项总长度最多40字节,SACK块通常最多3个(每个块8字节,加上Kind和Length共2字节,3个块占用26字节)。
- 如果乱序严重且块数超过限制,接收方需选择最重要的块报告(如最老的或最新的块)。
-
SACK攻击风险:
- 恶意接收方可伪造SACK块,诱使发送方错误认为数据已送达,可能导致数据不被重传(已被防护机制如SACK过滤限制)。
-
与其它机制的交互:
- 必须与重复确认计数结合,避免对轻微乱序过度反应。
- 在流量控制(零窗口)期间,SACK仍可发送,告知发送方哪些数据已接收,但发送方需等待窗口打开。
七、总结
- SACK通过“精确反馈”已接收的数据块,极大改善了TCP在乱序和多重丢包场景下的重传效率。
- 接收方生成SACK块,发送方利用SACK信息进行选择性重传,避免不必要的重传,提升吞吐量。
- 实际中,SACK是TCP高性能传输的关键选项之一,常与快速重传、快速恢复协同工作,是现代TCP实现(如Linux内核)的标准功能。