TCP的SACK与乱序报文段的处理机制详解
字数 2466 2025-12-14 14:23:48

TCP的SACK与乱序报文段的处理机制详解


一、知识点描述

在标准的TCP确认机制中,接收方只能通过累计确认(ACK)向发送方确认最后一个按序到达的字节。如果网络中发生报文段乱序(Out-of-Order),即使接收方已经收到了后续的一些报文段,发送方也必须等待缺失的报文段重传,这可能导致不必要的性能下降。

选择性确认(SACK, Selective Acknowledgment) 是一种TCP选项,允许接收方明确告知发送方哪些不连续的报文段已经成功接收,从而让发送方只重传真正缺失的部分,而不是盲目重传所有未确认的数据。这对于处理乱序多重丢包场景至关重要。


二、核心背景知识回顾

  1. 累计确认的缺陷

    • 接收方只能ACK“期待接收的下一个字节序号”。
    • 如果报文段4、5、6乱序到达(比如顺序是5、6、4),即使5和6到达了,接收方仍会一直发送ACK=4(表示期待4),直到4到达。
    • 发送方看到重复的ACK=4,可能触发快速重传,但实际只需重传4即可。
  2. 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。

步骤分解

  1. 接收方收到Seq=1:1000:

    • 发送ACK=1001(期待1001),无SACK。
  2. 收到Seq=2001:3000(乱序):

    • 期待的还是1001,但已收到2001-3000。
    • 发送ACK=1001,SACK块=[2001,3000)。
  3. 收到Seq=3001:4000(继续乱序):

    • 此时已有两个不连续块:2001-3000、3001-4000,可合并为[2001,4000)。
    • 发送ACK=1001,SACK块=[2001,4000)。
  4. 收到Seq=1001:2000(期待的报文到达):

    • 此时从1001到4000的数据全部连续。
    • 发送ACK=4001(累计确认点跳到4001),SACK可省略。
  5. 收到Seq=4001:5000:

    • 发送ACK=5001。

关键点:接收方通过SACK让发送方知道“2001-4000已收到”,发送方即使看到重复ACK=1001,也不会重传2001-4000,只需考虑重传1001-2000(如果判断丢失)。


五、SACK与快速重传/快速恢复的协同

  1. 触发快速重传:当发送方收到3个重复ACK(ACK=1001),且SACK块显示有新的数据块到达,发送方推断报文段1001-2000可能丢失。
  2. 选择性重传:发送方检查未确认的数据段,只重传未被SACK覆盖的段落(即1001-2000)。
  3. 拥塞控制调整
    • 执行快速恢复,拥塞窗口(cwnd)减半,并进入快速恢复阶段。
    • 每收到一个重复ACK(带有SACK),表示有数据离开网络,cwnd可适当增加,允许发送新数据。

六、SACK的局限性与注意事项

  1. SACK块数量限制

    • TCP选项总长度最多40字节,SACK块通常最多3个(每个块8字节,加上Kind和Length共2字节,3个块占用26字节)。
    • 如果乱序严重且块数超过限制,接收方需选择最重要的块报告(如最老的或最新的块)。
  2. SACK攻击风险

    • 恶意接收方可伪造SACK块,诱使发送方错误认为数据已送达,可能导致数据不被重传(已被防护机制如SACK过滤限制)。
  3. 与其它机制的交互

    • 必须与重复确认计数结合,避免对轻微乱序过度反应。
    • 流量控制(零窗口)期间,SACK仍可发送,告知发送方哪些数据已接收,但发送方需等待窗口打开。

七、总结

  • SACK通过“精确反馈”已接收的数据块,极大改善了TCP在乱序和多重丢包场景下的重传效率。
  • 接收方生成SACK块,发送方利用SACK信息进行选择性重传,避免不必要的重传,提升吞吐量。
  • 实际中,SACK是TCP高性能传输的关键选项之一,常与快速重传、快速恢复协同工作,是现代TCP实现(如Linux内核)的标准功能。
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 :选项总字节数(包括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字节: 场景 :网络乱序,到达顺序为: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内核)的标准功能。