Skip to main content

6. 用户数据传输 (User Data Transfer)

本章描述了SCTP端点之间的用户数据传输机制。

6.1. DATA块的传输 (Transmission of DATA Chunks)

SCTP端点通过DATA块在已建立的关联上交换用户消息。

6.1.1. 有效载荷数据 (Payload Data)

发送方应该 (SHOULD) 使用"路径MTU发现 (Path MTU Discovery)"(如[RFC4821]中定义)来确定到目的地的适当分段大小。

发送方可以 (MAY) 将用户消息分段为多个DATA块,每个块携带用户消息的一部分。接收方将使用流序列号 (Stream Sequence Number) 和片段标志(B位和E位)来重新组装消息。

当用户消息被分段为多个DATA块时:

  • 第一个片段必须 (MUST) 设置B位为1,E位为0
  • 中间片段必须 (MUST) 设置B位为0,E位为0
  • 最后一个片段必须 (MUST) 设置B位为0,E位为1
  • 未分段的消息必须 (MUST) 设置B位为1,E位为1

所有携带同一用户消息片段的DATA块必须 (MUST) 具有相同的流标识符 (Stream Identifier) 和流序列号 (Stream Sequence Number)。

6.1.2. 传输序列号 (Transmission Sequence Number, TSN)

每个DATA块必须 (MUST) 包含一个有效的TSN。TSN是一个32位序列号,在关联初始化期间交换的初始TSN值开始,每发送一个DATA块递增1。

TSN空间是循环的,比较使用Serial Number Arithmetic(如[RFC1982]中定义)。

发送方不得 (MUST NOT) 在DATA块中使用保留的TSN值(即,在其对等方宣告的接收窗口之外的TSN)。

6.1.3. 拥塞控制 (Congestion Control)

SCTP端点必须 (MUST) 实现拥塞控制,以避免网络拥塞。SCTP使用类似于TCP的拥塞控制机制。

每个SCTP关联维护以下拥塞控制参数:

  • cwnd (拥塞窗口, Congestion Window): 在未收到确认的情况下可以发送的数据量上限
  • ssthresh (慢启动阈值, Slow Start Threshold): 确定何时从慢启动切换到拥塞避免的阈值
  • rwnd (接收窗口, Receiver Window): 对等方宣告的可用缓冲空间

发送方在任何时候可以传输的未确认数据量不得 (MUST NOT) 超过min(cwnd, rwnd)

慢启动 (Slow Start):

  • 在关联开始时或超时后,将cwnd设置为不超过2*MTU
  • 每次收到SACK且所有确认的数据在慢启动阶段发送时,cwnd增加不超过确认的字节数,但增量不超过MTU

拥塞避免 (Congestion Avoidance):

  • 当cwnd > ssthresh时,每个RTT增加cwnd最多1*MTU
  • 实现应该 (SHOULD) 使用"适当字节计数 (Appropriate Byte Counting)"(如[RFC3465]中定义)

快速重传和快速恢复 (Fast Retransmit and Fast Recovery):

  • 当接收到4个连续的SACK报告缺失同一TSN时,发送方应该 (SHOULD) 立即重传该TSN,无需等待重传定时器到期

6.1.4. 捆绑 (Bundling)

SCTP端点可以 (MAY) 在单个SCTP数据包中捆绑多个DATA块和控制块,只要总大小不超过当前路径MTU。

捆绑的好处包括:

  • 减少数据包头部开销
  • 提高网络效率
  • 减少系统调用次数

发送方应该 (SHOULD) 尝试在单个数据包中捆绑尽可能多的数据,但不得 (MUST NOT) 延迟DATA块传输仅为等待更多数据进行捆绑。

6.2. 接收DATA块时的确认 (Acknowledgement on Reception of DATA Chunks)

接收SCTP端点必须 (MUST) 使用SACK (Selective Acknowledgement) 块来确认接收到的DATA块。

6.2.1. SACK生成规则 (SACK Generation Rules)

接收方应该 (SHOULD) 使用以下规则生成SACK:

  1. 延迟确认 (Delayed Acknowledgement):

    • 接收方不应该 (SHOULD NOT) 为每个接收到的数据包立即发送SACK
    • 接收方应该 (SHOULD) 延迟发送SACK最多200ms
    • 如果收到第二个数据包,必须 (MUST) 立即发送SACK(不再延迟)
  2. 立即确认情况:

    • 当检测到间隙时(接收到乱序DATA块)
    • 当接收到的DATA块填补了之前的间隙
    • 当接收到重复的TSN
  3. SACK内容:

    • Cumulative TSN Ack: 最高连续接收的TSN
    • Gap Ack Blocks: 指示在累积点之后接收到的连续TSN范围
    • Duplicate TSNs: 列出重复接收的TSN

6.2.2. SACK处理 (SACK Processing)

发送方在接收到SACK时必须 (MUST)

  1. 更新其累积确认点到SACK中指示的Cumulative TSN Ack
  2. 将Gap Ack Blocks中确认的DATA块标记为已确认
  3. 更新拥塞窗口和慢启动阈值
  4. 根据需要调度重传

6.2.3. 接收窗口更新 (Receiver Window Update)

SACK块包含advertised receiver window credit (a_rwnd),指示接收方的可用缓冲空间。

接收方应该 (SHOULD) 在SACK中准确报告其可用缓冲空间。接收方不得 (MUST NOT) 减少已宣告的窗口大小,除非它已经消耗了相应的缓冲空间。

6.3. 重传定时器管理 (Management of Retransmission Timer)

SCTP使用重传定时器来确保可靠传输。每个目的传输地址维护自己的重传定时器。

6.3.1. RTO计算 (RTO Calculation)

重传超时 (Retransmission Timeout, RTO) 使用类似于TCP的算法计算:

SRTT = 平滑往返时间 (Smoothed Round-Trip Time)
RTTVAR = 往返时间变化 (Round-Trip Time Variation)

初始值:
RTO.Initial = 3秒 (推荐值)
RTO.Min = 1秒
RTO.Max = 60秒

首次RTT测量 (R):
SRTT = R
RTTVAR = R/2
RTO = SRTT + 4 * RTTVAR

后续RTT测量 (R'):
RTTVAR = (1 - Beta) * RTTVAR + Beta * |SRTT - R'|
SRTT = (1 - Alpha) * SRTT + Alpha * R'
RTO = SRTT + 4 * RTTVAR

其中: Alpha = 1/8, Beta = 1/4

每次重传时,RTO应该 (SHOULD) 加倍(指数退避),直到达到RTO.Max。

6.3.2. 定时器规则 (Timer Rules)

T3-rtx定时器 (重传定时器):

  • 当DATA块首次发送到目的地时,如果该目的地的T3-rtx定时器未运行,则必须 (MUST) 启动它
  • 当所有发送到目的地的未确认DATA块都被确认时,必须 (MUST) 停止该目的地的T3-rtx定时器
  • 当T3-rtx定时器到期时,必须 (MUST) 重传该目的地上最早的未确认DATA块

T3-rtx超时处理:

  1. 标记目的地为不活动(如果适用)
  2. 将ssthresh设置为max(cwnd/2, 4*MTU)
  3. 将cwnd设置为1*MTU
  4. 重传最早的未确认DATA块
  5. 将RTO加倍

6.3.3. Heartbeat机制 (Heartbeat Mechanism)

为了监控目的地的可达性,SCTP端点应该 (SHOULD) 定期向每个空闲目的地发送HEARTBEAT块。

HEARTBEAT间隔应该 (SHOULD) 可配置,推荐默认值为30秒。

当HEARTBEAT发送时:

  • 启动Heartbeat定时器
  • 在HEARTBEAT中包含发送时间戳和目的地址信息

当收到HEARTBEAT ACK时:

  • 计算RTT
  • 更新RTO
  • 将目的地标记为活动

如果HEARTBEAT超时(未收到HEARTBEAT ACK):

  • 增加目的地的错误计数
  • 如果错误计数超过阈值,将目的地标记为不活动

6.4. 多宿主SCTP端点 (Multi-Homed SCTP Endpoints)

SCTP支持多宿主端点,即具有多个IP地址的端点。

6.4.1. 主路径和备用路径 (Primary and Alternate Paths)

每个SCTP端点维护:

  • 主路径 (Primary Path): 用于正常数据传输的首选路径
  • 备用路径 (Alternate Paths): 当主路径失败时使用的路径

端点应该 (SHOULD) 优先通过主路径发送数据,只有在主路径不可用时才使用备用路径。

6.4.2. 路径选择 (Path Selection)

发送方应该 (SHOULD)

  • 使用主路径发送新数据
  • 使用备用路径进行重传(如果主路径失败)
  • 定期使用HEARTBEAT探测所有路径

当主路径被确定为不活动时,发送方应该 (SHOULD) 选择一个活动的备用路径作为新的主路径。

6.4.3. 路径故障检测 (Path Failure Detection)

路径被认为失败当:

  • 连续多次传输失败(达到路径最大重传次数 Path.Max.Retrans)
  • 连续多次HEARTBEAT超时

当所有路径都失败时,关联应该 (SHOULD) 报告给上层,并可能被终止。

6.5. 流标识符和流序列号 (Stream Identifier and Stream Sequence Number)

SCTP支持多个并发流,每个流由流标识符 (Stream Identifier, SI) 唯一标识。

流标识符 (Stream Identifier, SI):

  • 16位值,范围0到65535
  • 在关联初始化期间协商流的数量
  • 每个流独立传送用户消息

流序列号 (Stream Sequence Number, SSN):

  • 16位值,每个流独立维护
  • 用于在接收方重新排序和重组消息
  • 按流递增

流提供了消息的逻辑分离,允许多个独立的数据流在同一关联上并发传输,避免队头阻塞 (Head-of-Line Blocking)。

6.6. 有序和无序传递 (Ordered and Unordered Delivery)

SCTP支持两种消息传递模式:

6.6.1. 有序传递 (Ordered Delivery)

默认模式。消息在每个流内按发送顺序传递给上层。

  • DATA块的U位设置为0
  • 使用流序列号确保顺序
  • 同一流的消息按SSN顺序传递

6.6.2. 无序传递 (Unordered Delivery)

消息一旦接收就立即传递给上层,不管顺序。

  • DATA块的U位设置为1
  • 流序列号被忽略
  • 接收后立即传递,不等待之前的消息

无序传递适用于不需要顺序保证的实时数据(如视频流)。

6.7. 报告接收DATA TSN中的间隙 (Report Gaps in Received DATA TSNs)

当接收方检测到接收序列中的间隙时(即收到乱序数据),必须 (MUST) 在SACK中报告这些间隙。

Gap Ack Block格式:

Gap Ack Block Start: 相对于Cumulative TSN Ack的偏移
Gap Ack Block End: 相对于Cumulative TSN Ack的偏移

例如,如果Cumulative TSN Ack = 100,且接收到TSN 102-105:

Gap Ack Block Start = 2  (102 - 100)
Gap Ack Block End = 5 (105 - 100)

接收方可以 (MAY) 在单个SACK中报告多个间隙块。

6.8. CRC32c校验和计算 (CRC32c Checksum Calculation)

SCTP使用CRC32c (Castagnoli) 作为其校验和算法,提供比简单校验和更强的错误检测能力。

6.8.1. 校验和计算步骤 (Checksum Calculation Steps)

  1. 将SCTP数据包的校验和字段设置为全0
  2. 对整个SCTP数据包(包括SCTP通用头和所有块)计算CRC32c
  3. 将计算的CRC32c值放入校验和字段

CRC32c多项式:

x^32 + x^28 + x^27 + x^26 + x^25 + x^23 + x^22 + x^20 + x^19 + 
x^18 + x^14 + x^13 + x^11 + x^10 + x^9 + x^8 + x^6 + x^0

接收方必须 (MUST) 验证接收到的每个SCTP数据包的CRC32c校验和。如果校验和不匹配,必须 (MUST) 静默丢弃该数据包。


本章节完整覆盖了SCTP用户数据传输的核心机制,包括可靠传输、拥塞控制、多宿主支持和流多路复用。