跳到主要内容

6. SCTP 在数据通道中的用法

6.1. SCTP 协议考虑

必须使用 [RFC8261] 中描述的 SCTP 数据包的 DTLS 封装.

此 SCTP 栈及其上层必须支持使用多个 SCTP 流. 用户消息可以按顺序或无序发送, 并可使用部分可靠性或完全可靠性.

需要以下 SCTP 协议扩展:

  • 必须支持 [RFC6525] 中定义的流重配置扩展. 它用于关闭通道.
  • 必须使用 [RFC5061] 中定义的动态地址重配置扩展, 以发出支持 [RFC6525] 中定义的流重置扩展的信号. [RFC5061] 的其他特性是可选的.
  • 必须支持 [RFC3758] 中定义的部分可靠性扩展. 除 [RFC3758] 中定义的定时可靠性 PR-SCTP 策略外, 还必须支持 [RFC7496] 中定义的有限重传策略. 将重传次数限制为零并结合无序交付, 可提供类似 UDP 的服务, 其中每条用户消息只发送一次, 并按接收顺序交付.

应当使用 [RFC8260] 中定义的消息交织支持.

6.2. SCTP 关联管理

在 WebRTC 上下文中, 当 WebRTC PeerConnection 的两个端点同意打开 SCTP 关联时, 该关联会被建立; 这通常由 JavaScript Session Establishment Protocol (JSEP) 协商, 而 JSEP 通常是 Session Description Protocol (SDP) [RFC8829] 的交换. 它将使用通过 ICE 选择的 DTLS 连接, 并且通常会通过 BUNDLE 或等效机制与用于为 SRTP 媒体流导出密钥的 DTLS 连接共享.

SCTP 关联建立期间协商的流数量应当为 65535, 这是关联建立期间可协商的最大流数量.

SCTP 支持两种终止 SCTP 关联的方式. 第一种方式是优雅终止, 使用一种过程来确保关联关闭期间没有消息丢失. 第二种方式是非优雅终止, 一方可以直接中止关联.

每个 SCTP 端点都会通过监视用户消息和测试消息的重传次数, 持续监督其对等方的可达性. 如果发生过多重传, 关联会以非优雅方式终止.

如果 SCTP 关联以优雅方式关闭, 其所有数据通道都会关闭. 在非优雅拆除的情况下, 所有数据通道也会关闭, 但如果可能, 应当提供错误指示.

6.3. SCTP 流

SCTP 将流定义为存在于到另一个 SCTP 端点的 SCTP 关联内的单向逻辑通道. 流用于提供按序交付概念以及复用. 每条用户消息都在特定流上发送, 可以是有序的, 也可以是无序的. 仅对同一流上发送的有序消息保持排序.

6.4. 数据通道定义

数据通道的定义使其配套的应用级 API 能够紧密映射 WebSockets 的 API, 这意味着双向数据流以及一个称为 'label' 的文本字段, 用于标识数据通道的含义.

数据通道的实现是一对 SCTP 流: 一个传入流和一个传出流, 二者具有相同的 SCTP 流标识符. 这些 SCTP 流标识符如何选择取决于协议和实现. 这允许双向通信.

此外, 每个数据通道在每个方向上具有以下属性:

  • 可靠或不可靠的消息传输: 在不可靠传输的情况下, 使用相同级别的不可靠性. 注意, 在 SCTP 中, 这是 SCTP 用户消息的属性, 而不是 SCTP 流的属性.
  • 已发送消息的有序或乱序消息交付: 注意, 在 SCTP 中, 这是 SCTP 用户消息的属性, 而不是 SCTP 流的属性.
  • 一个优先级, 它是 2 字节无符号整数: 这些优先级必须按 [RFC8260] 中支持交织的相应流调度器定义, 解释为加权公平排队调度优先级. 对 WebRTC 使用而言, 所用值应当是 128 ("below normal"), 256 ("normal"), 512 ("high") 或 1024 ("extra high") 之一.
  • 可选 label.
  • 可选 protocol.

注意, 对于使用 [RFC8832] 中指定协议协商的数据通道, 上述所有属性在两个方向上都相同.

6.5. 打开数据通道

可以通过 SCTP 关联内的协商 (称为带内协商) 或带外协商打开数据通道. 带外协商定义为任何导致就通道参数及其创建达成一致的方法. 其细节不在本文档范围内. 使用数据通道的应用需要在两个端点上一致地使用协商方法.

[RFC8832] 指定了一种用于带内协商的简单协议.

当一方希望使用带外协商打开通道时, 它会选择一个流. 除非另有定义或协商, 流会根据 DTLS 角色选择 (客户端选择偶数流标识符, 服务器选择奇数流标识符). 但是, 应用负责避免与现有流发生冲突. 如果它尝试复用属于现有数据通道的流, 添加操作必须失败. 除了选择流之外, 应用还应当确定用于发送消息的选项. 应用必须以应用特定方式确保对等方的应用也知道所选要使用的流, 以及从该侧发送数据的选项.

6.6. 在数据通道上传输用户数据

除非选项发生改变或更高层指定逐消息选项, 否则在数据通道两个方向上发送的所有数据都必须使用打开数据通道时定义的可靠性, 通过底层流发送.

SCTP 的面向消息特性用于保留用户消息的消息边界. 因此, 发送方禁止把多条应用消息放入一条 SCTP 用户消息中. 除非使用已弃用的基于 PPID 的分片和重组, 否则发送方必须在每条 SCTP 用户消息中只包含一条应用消息.

SCTP Payload Protocol Identifiers (PPID) 用于发出 "payload data" 的解释信号. 必须使用以下 PPID (见第 8 节):

  • WebRTC String: 标识以 UTF-8 编码的非空 JavaScript 字符串.
  • WebRTC String Empty: 标识以 UTF-8 编码的空 JavaScript 字符串.
  • WebRTC Binary: 标识非空 JavaScript 二进制数据 (ArrayBuffer, ArrayBufferView 或 Blob).
  • WebRTC Binary Empty: 标识空 JavaScript 二进制数据 (ArrayBuffer, ArrayBufferView 或 Blob).

SCTP 不支持发送空用户消息. 因此, 如果必须发送空消息, 则使用适当的 PPID (WebRTC String Empty 或 WebRTC Binary Empty), 并发送一个零字节的 SCTP 用户消息. 当收到带有这些 PPID 之一的 SCTP 用户消息时, 接收方必须忽略该 SCTP 用户消息, 并把它作为空消息处理.

PPID "WebRTC String Partial" 和 "WebRTC Binary Partial" 的用法已弃用. 它们曾用于属于可靠且有序数据通道的用户消息的基于 PPID 的分片和重组.

如果收到带有不支持 PPID 的消息, 或者接收方检测到与所接收消息相关的某些错误条件 (例如非法排序), 接收方应当关闭相应的数据通道. 这尤其意味着, 使用额外 PPID 的扩展未经事先协商不能使用.

[RFC4960] 中指定的 SCTP 基础协议不支持用户消息交织. 因此, 发送一条大型用户消息可能独占 SCTP 关联. 为克服这一限制, [RFC8260] 定义了支持消息交织的扩展, 应当使用该扩展. 只要不支持消息交织, 发送方就应当把最大消息大小限制为 16 KB, 以避免独占.

建议将消息大小保持在一定范围内, 因为应用无法支持任意大的单条消息. 该限制必须协商, 例如通过使用 [RFC8841].

发送方应当禁用 Nagle 算法 (见 [RFC1122]) 以最小化延迟.

6.7. 关闭数据通道

关闭数据通道必须通过重置相应传出流 [RFC6525] 来发出信号. 这意味着, 如果一方决定关闭数据通道, 它会重置相应的传出流. 当对等方看到某个传入流被重置时, 它也会重置其相应的传出流. 一旦完成此过程, 数据通道即关闭. 重置流会把该流的 Stream Sequence Numbers (SSN) 设回 'zero', 并向应用层发出相应通知, 表明已执行重置. 执行重置后, 流可重新使用.

[RFC6525] 还保证所有消息会在流被重置之前被交付 (或放弃).