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:
-
延迟确认 (Delayed Acknowledgement):
- 接收方不应该 (SHOULD NOT) 为每个接收到的数据包立即发送SACK
- 接收方应该 (SHOULD) 延迟发送SACK最多200ms
- 如果收到第二个数据包,必须 (MUST) 立即发送SACK(不再延迟)
-
立即确认情况:
- 当检测到间隙时(接收到乱序DATA块)
- 当接收到的DATA块填补了之前的间隙
- 当接收到重复的TSN
-
SACK内容:
- Cumulative TSN Ack: 最高连续接收的TSN
- Gap Ack Blocks: 指示在累积点之后接收到的连续TSN范围
- Duplicate TSNs: 列出重复接收的TSN
6.2.2. SACK处理 (SACK Processing)
发送方在接收到SACK时必须 (MUST):
- 更新其累积确认点到SACK中指示的Cumulative TSN Ack
- 将Gap Ack Blocks中确认的DATA块标记为已确认
- 更新拥塞窗口和慢启动阈值
- 根据需要调度重传
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超时处理:
- 标记目的地为不活动(如果适用)
- 将ssthresh设置为
max(cwnd/2, 4*MTU) - 将cwnd设置为1*MTU
- 重传最早的未确认DATA块
- 将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)
- 将SCTP数据包的校验和字段设置为全0
- 对整个SCTP数据包(包括SCTP通用头和所有块)计算CRC32c
- 将计算的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用户数据传输的核心机制,包括可靠传输、拥塞控制、多宿主支持和流多路复用。