数据通信

数据通信 #

我可以从 WebRTC 的数据通信中获得什么? #

WebRTC 提供用于数据通信的数据通道。在两个 peer 之间,你可以打开 65,534 个数据通道。 数据通道基于数据报,并且每个通道都有其自己的持久性设置。默认设置下,每个数据通道都能保证有序交付。

如果你从传递媒体数据的角度开始接触 WebRTC,可能数据通道看起来是一种浪费。当我只使用 HTTP 或 WebSocket 就能传递数据的时候,为什么需要整个数据通道子系统呢?

数据通道的真正强大之处在于,你可以将它们配置为像 UDP 一样进行无序 / 有损传递。 对于低延迟和高性能的情况,这是必需的。你可以测量背压,并确保你仅发送网络支持的最大数据量。

它是如何工作的? #

WebRTC 使用RFC 4960中定义的流控制传输协议(SCTP)。SCTP 是一种传输层协议,旨在替代 TCP 或 UDP。对于 WebRTC,我们将 SCTP 用作在 DTLS 连接上运行的应用层协议。

SCTP 为你提供流,并且每个流都可以独立配置。WebRTC 数据通道只是基于流的简单抽象。有关持久性和顺序的设置会被直接传递到 SCTP Agent 中。

数据通道具有 SCTP 无法表达的某些功能,例如通道标签。为了解决该问题,WebRTC 使用了RFC 8832中定义的数据通道建立协议(DCEP)。DCEP 定义了一条消息,用于传递通道标签和协议。

DCEP #

DCEP 只有两个消息 DATA_CHANNEL_OPENDATA_CHANNEL_ACK。对于打开的每个数据通道,远端必须以 ack 响应。

DATA_CHANNEL_OPEN #

该消息由希望打开数据通道的 WebRTC Agent 发送。

封包格式 #

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Message Type |  Channel Type |            Priority           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Reliability Parameter                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Label Length          |       Protocol Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
\                                                               \
/                             Label                             /
\                                                               \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
\                                                               \
/                            Protocol                           /
\                                                               \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

消息类型(Message Type) #

消息类型是一个静态值 0x03

通道类型(Channel Type) #

Channel Type controls durability/ordering attributes of the channel. It may have the following values: 通道类型控制通道的持久性 / 排序属性。它可能具有以下值:

  • DATA_CHANNEL_RELIABLE (0x00) - 没有消息丢失,消息依序到达。
  • DATA_CHANNEL_RELIABLE_UNORDERED (0x80) - 没有消息丢失,但消息可能乱序到达。
  • DATA_CHANNEL_PARTIAL_RELIABLE_REXMIT (0x01) - 按照请求中的次数重试发送后,消息可能会丢失,但消息将依序到达。
  • DATA_CHANNEL_PARTIAL_RELIABLE_REXMIT_UNORDERED (0x81) - 按照请求中的次数重试发送后,消息可能会丢失,且消息可能乱序到达。
  • DATA_CHANNEL_PARTIAL_RELIABLE_TIMED (0x02) - 如果没有在请求的时间内到达,消息可能会丢失,但消息将依序到达。
  • DATA_CHANNEL_PARTIAL_RELIABLE_TIMED_UNORDERED (0x82) - 如果没有在请求的时间内到达,消息可能会丢失,且消息可能乱序到达。

优先级(Priority) #

数据通道的优先级。具有较高优先级的数据通道将首先被调度。较大的低优先级用户消息不会耽误高优先级用户消息的发送。

可靠性参数 #

如果数据通道类型的前缀为 DATA_CHANNEL_PARTIAL_RELIABLE,则不同的后缀对应的参数配置如下:

  • REXMIT - 定义发送方重试发送消息的次数,超出此次数将放弃尝试。
  • TIMED - 定义发送方重试发送消息的时间(以毫秒为单位),超出此时间将放弃尝试。

标签(Label) #

一个包含数据通道名称的 UTF-8 编码的字符串。可能为空。

协议(Protocol) #

如果这里为空字符串,则协议未指定。如果是非空字符串,则这里应指定一个协议,可指定的协议请参考RFC 6455中定义的 “WebSocket 子协议名称注册表 " 中的注册协议。

DATA_CHANNEL_ACK #

WebRTC Agent 发送此消息以确认此数据通道已打开。

封包格式 #

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Message Type |
+-+-+-+-+-+-+-+-+

流控传输协议(SCTP) #

SCTP 是 WebRTC 数据通道背后的真正动力。它提供了数据通道的以下所有功能:

  • 多路复用
  • 使用类似 TCP 的重传机制进行可靠传递
  • 部分可靠性选项
  • 避免拥塞
  • 流量控制

为了理解 SCTP,我们将分三个部分进行探讨。我们的目标是,在本章之后,你将拥有足够的知识来自行调试和学习 SCTP 的详细信息。

概念 #

SCTP 协议功能很多。本节仅涵盖 WebRTC 使用的 SCTP 部分。 SCTP 中,WebRTC 不使用的功能包括多宿主(multi-homing)和路径选择。

经过 20 多年的发展,SCTP 变得难以完全掌握。

关联(Association) #

关联是用于 SCTP 会话的术语。这是两个 SCTP Agent 在通信时共享的状态。

#

一个流是用户数据的一个双向序列。创建数据通道时,实际上只是在创建一个 SCTP 流。每个 SCTP 关联都包含一个流列表。可以为每个流配置不同的可靠性类型。

WebRTC 只允许你在创建流时进行配置,而 SCTP 实际上允许随时更改配置。

基于数据报 #

SCTP 将数据构造为数据报,而不是字节流。发送和接收数据就像是使用 UDP 而不是 TCP。 你无需添加任何额外的代码即可通过一个流传输多个文件。

SCTP 消息没有像 UDP 这样的大小限制。单个 SCTP 消息的大小可以达到几个 GB。

块(Chunks) #

SCTP 协议由块组成。有许多不同类型的块。这些块用于所有通信。 用户数据,连接初始化,拥塞控制等,全部通过块完成。

每个 SCTP 数据包都包含一个块列表。因此,在一个 UDP 数据包中,你可以有多个块承载来自不同流的消息。

传输序列号 #

传输序列号(TSN)是 DATA 块的全局唯一标识符。DATA 块承载用户希望发送的所有消息。TSN 很重要,因为它可以帮助接收方确定数据包是否丢失或乱序。

如果接收方注意到缺少 TSN,则在数据完整获取之前,它不应将数据提供给用户。

流标识符 #

每个流都有一个唯一的标识符。当你创建带有显式 ID 的数据通道时,实际上是将其作为流标识符直接传递到 SCTP 中。如果你没有传递 ID,则会为你自动选择流标识符。

有效负载协议标识符 #

每个 DATA 块还具有一个有效负载协议标识符(PPID)。这用于唯一地标识正在交换的数据类型。 SCTP 具有许多 PPID,但是 WebRTC 仅使用以下五种:

  • WebRTC DCEP (50) - DCEP 消息。
  • WebRTC String (51) - Datachannel 字符串消息。
  • WebRTC Binary (53) - Datachannel 二进制消息。
  • WebRTC String Empty (56) - 长度为 0 的 Datachannel 字符串消息。
  • WebRTC Binary Empty (57) - 长度为 0 的 Datachannel 二进制消息。

协议 #

以下是 SCTP 协议使用的一些块。这不是一个详尽的演示。只提供了足够的结构让状态机运作起来。

每个块均以 type 字段开头。在块列表之前,还有一个头字段。

DATA 块 #

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Type = 0    | Reserved|U|B|E|    Length                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                              TSN                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      Stream Identifier        |   Stream Sequence Number      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                  Payload Protocol Identifier                  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
\                                                               \
/                            User Data                          /
\                                                               \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

DATA 块是交换所有用户数据的方式。下面是对 DATA 块更详细的说明,数据就是这样通过数据通道被发送的。

如果是无序数据包,则将 U 位设置为 1。我们可以忽略流序列号(Stream Sequence Number)。

BE 是开始位和结束位。如果要发送的消息对于单个 DATA 块而言太大,则需要将其分片成多个 DATA 块发送。 SCTP 使用 比特位 BE 以及序列号(TSN)来描述消息分包。

  • B=1, E=0 - 用户消息的第一个分片。
  • B=0, E=0 - 用户消息的中间的分片。
  • B=0, E=1 - 用户消息的最后一个分片。
  • B=1, E=1 - 未分片的用户消息。

TSNTransmission Sequence Number,一个 DATA chunk 的唯一标识符。它是一个递增的 32-bit 数,在达到最大值 4,294,967,295 之后,继续从 0 开始递增。

Stream Identifier(流标识符)是该数据所属流的唯一标识符。

Stream Sequence Number , 标识一个用户消息。它是一个递增的 16-bit 数,在 达到最大值 65535 之后,继续从 0 开始递增。 比特位 U 设置为 1 时,表示无序消息包,Stream Sequence Number 可以忽略。 比特位 U 设置为 0 时,表示有序消息包,该编号用于确定消息包的顺序。 与 TSN 类似,但是 Stream Sequence Number 以一个用户消息的粒度递增,TSN 以一个 Chunk 的粒度递增。

Payload Protocol Identifier(有效负载协议标识符)是流过此流的数据类型。对于 WebRTC 而言,它可能是 DCEP,String 或 Binary。

User Data(用户数据)就是你要发送的内容。通过 WebRTC Data Channel 发送的所有数据均通过 DATA 块传输。

INIT 块 #

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Type = 1    |  Chunk Flags  |      Chunk Length             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Initiate Tag                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Advertised Receiver Window Credit (a_rwnd)          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Number of Outbound Streams   |  Number of Inbound Streams    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          Initial TSN                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
\                                                               \
/              Optional/Variable-Length Parameters              /
\                                                               \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

INIT 块开始创建一个关联(association)的过程。

Initiate Tag(启动标签)用于生成 Cookie。Cookies 技术在中间人攻击和 DoS 保护中可能会被用到。在状态机章节中对它们进行了更详细的描述。

Advertised Receiver Window Credit(广播接收者窗口信用值)用于 SCTP 的拥塞控制。它传达了接收方已为此关联分配了多大的缓冲区。

Number of Outbound/Inbound Streams(出站 / 入站流的数量)通知该 Agent 支持多少个流。

Initial TSN(初始 TSN)是随机的 uint32,本地 TSN 以这个值开始计数。

Optional Parameters(可选参数)允许 SCTP 向协议引入新功能。

SACK 块 #

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Type = 3    |Chunk  Flags   |      Chunk Length             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      Cumulative TSN Ack                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Advertised Receiver Window Credit (a_rwnd)           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Number of Gap Ack Blocks = N  |  Number of Duplicate TSNs = X |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Gap Ack Block #1 Start       |   Gap Ack Block #1 End        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/                                                               /
\                              ...                              \
/                                                               /
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Gap Ack Block #N Start      |  Gap Ack Block #N End         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Duplicate TSN 1                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/                                                               /
\                              ...                              \
/                                                               /
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Duplicate TSN X                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

SACK(选择性确认)块是接收方通知发送方它已收到数据包信息的方式。在发送方获得针对 TSN 的 SACK 之前,它将重新发送有问题的 DATA 块。然而,SACK 的作用不只是更新 TSN 信息。

Cumulative TSN ACK(累积 TSN ACK)是已收到的最高 TSN。

Advertised Receiver Window Credit(广播接收者窗口信用值)是接收方的缓冲区大小。如果可用内存增加,接收方可以在会话期间更改此设置。

Cumulative TSN ACK(累积 TSN ACK)后面,是 Ack Blocks 的 TSN。 这个方法用来解决传送的数据包中有缺口的问题。假设我们收到了带有 TSN100,102,103104 的 DATA 块。Cumulative TSN ACK 应该是 100,但可以使用 Ack Blocks 来告诉发送方不需要重新发送 102,103104

Duplicate TSN(重复 TSN)会通知发送方,它已经不止一次的接收了哪些 DATA 数据块。

HEARTBEAT 块 #

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Type = 4    | Chunk  Flags  |      Heartbeat Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
\                                                               \
/            Heartbeat Information TLV (Variable-Length)        /
\                                                               \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

HEARTBEAT 块用于断言远端仍能响应。 当你不发送任何 DATA 数据块,且需要保持 NAT 映射打开时,这很有用。

ABORT 块 #

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Type = 6    |Reserved     |T|           Length              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/                                                               /
\               Zero or more Error Causes                       \
/                                                               /
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

ABORT 块用于关联的突然关闭。当一侧进入错误状态时使用。正常结束连接使用 SHUTDOWN 块。

SHUTDOWN 块 #

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Type = 7    | Chunk  Flags  |      Length = 8               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      Cumulative TSN Ack                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

SHUTDOWN 块将正常关闭 SCTP 关联。 每个 Agent 将其发送的最后一个 TSN 通知给远端。这样可以确保不会丢失任何数据包。(如果有资源仍在使用中的话,)WebRTC 不能正常关闭 SCTP 关联。你需要自行关闭所有数据通道。

Cumulative TSN ACK(累积 TSN ACK)是发送的最后一个 TSN。双方都知道在接收到此 TSN 对应的 DATA 块之前不要终止。

ERROR 块 #

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Type = 9    | Chunk  Flags  |           Length              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
\                                                               \
/                    One or more Error Causes                   /
\                                                               \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

ERROR 块用于通知远端 SCTP Agent:本端发生了非致命错误。

FORWARD TSN 块 #

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Type = 192  |  Flags = 0x00 |        Length = Variable      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      New Cumulative TSN                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Stream-1              |       Stream Sequence-1       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
\                                                               /
/                                                               \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Stream-N              |       Stream Sequence-N       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

FORWARD TSN 块将全局 TSN 向前移动。SCTP 这样做是为了允许跳过一些你不再关心的数据包。假设你发送了 10 11 12 13 14 15,这些数据包只有在它们全部到达后才有意义。而这些数据又对实时性很敏感,在这种情况下,如果数据收晚了,它们就没有用了。

如果你丢失了 1213,则不需要再发送 1415! SCTP 使用 FORWARD TSN 块来实现这一点。它告诉接收方,1415 将不再传递。

New Cumulative TSN(新的累积 TSN),是连接的新 TSN。此 TSN 之前的任何数据包都不会被保留。

Stream(流)和 Stream Sequence(流序列)用于将 Stream Sequence Number 的编号向前跳转。请参阅前面的 DATA 块以了解该字段的重要性。

状态机 #

这里是 SCTP 状态机中一些有趣的部分。WebRTC 并未使用 SCTP 状态机的所有功能,因此我们将没有用到的部分排除在外。我们还简化了一些组件,使它们更易于理解。

连接建立流程 #

INITINIT ACK 块用于交换 peer 的能力和配置。SCTP 在握手期间使用 cookie 来验证与之通信的 peer。 这是为了确保握手不会被拦截并防止 DoS 攻击。

INIT ACK 块包含 cookie。然后,使用 COOKIE ECHO 将 cookie 返回给其创建者。如果 cookie 验证成功,则发送 COOKIE ACK,并且准备交换 DATA 块。

连接的建立

连接关闭流程 #

SCTP 使用 SHUTDOWN 块。当 Agent 收到 SHUTDOWN 块时,它将等待直到收到请求的 Cumulative TSN ACK。这样,即使连接有损,用户也可以确保传送了所有数据。

Keep-Alive(保持活动)机制 #

SCTP 使用 HEARTBEAT REQUESTHEARTBEAT ACK 块使连接保持活动状态。它们以固定间隔发送,间隔时间可配置。如果数据包尚未到达,SCTP 还会将指数回退。

HEARTBEAT 块还包含一个时间值。两个关联可以用此来计算两个 Agent 之间的数据传递时间。