# RTC 入门 07：两端怎样找到能通话的网络路径

作者：Hex4C59 · 发布于 2026-10-15

原文：https://hex4c59.cc/articles/rtc-07-connection-setup/


小林的电脑和小周的手机都已登录同一个应用。小林按下呼叫，小周能看到来电，也能按下接听。两边的界面都显示“正在连接”，却一直没有声音。

既然呼叫消息能送到，声音为什么不能沿着同一条路过去？

呼叫消息通常经过应用服务器。这个服务器知道应该把“有人找你”通知给谁，却未必承担声音转发。两端还要交换通信参数、尝试网络路径、完成安全处理，再核对媒体是否真的开始传输。**业务消息送达，只完成了建立通话过程中的一部分。**

前六篇都从“已有一条媒体路径”出发，讨论声音的数据、时限、恢复和排队。这一篇把起点往前移：路径还没有时，两端怎样找到它。阅读不要求先学过网络编程；正文会先解释地址与端口。读完后，你应当能够对一段新的连接记录指出：哪些步骤已经有证据，下一步还该查什么。

## 账号找到了人，IP 和端口才开始找接收位置

假设小林的账号叫 A，小周的账号叫 B。应用服务器能查到 B 当前在线，将来电通知送给 B。这个账号解决的是“找谁”。

一份网络数据还需要知道“往哪里送”。先把三个东西分清：

- **IP（Internet Protocol，互联网协议）地址**标识网络中的地址位置。路由设备据此决定数据下一步往哪里转发。
- **端口**是传输协议中的编号。接收设备借助端口等信息，把数据交给相应的通信端点。
- **传输协议**规定传输层怎样处理数据。这里先讨论 **UDP（User Datagram Protocol，用户数据报协议）**：它把应用交付的数据作为数据报发送，不保证数据必达或按序到达。另一个常见协议 TCP（Transmission Control Protocol，传输控制协议）则提供可靠、有序的字节流。

例如 `UDP 192.168.1.10:50000` 表示使用 UDP，IP 是 `192.168.1.10`，端口是 `50000`。知道 IP 却不知道接收端口，还不足以给本例中的接收端发送数据。TCP 的同号端口也不能直接当成这个 UDP 端点。

小林和小周各在自己家里，两人的设备甚至可能都叫 `192.168.1.10`。这类私有地址可在不同内网中重复使用，不是可以让互联网用户按同一个地址直接找到的全球唯一位置。把自己的内网地址复制给对方，不能替代路径检查。

下面出现的 `192.0.2.x`、`198.51.100.x`、`203.0.113.x` 都是文档示例地址，端口也是教学设定；它们不是可以试连的公网服务。[^addresses]

## 先商量这次怎样通信：信令、SDP 和 Offer/Answer

双方除了找到地址，还要知道彼此准备传什么。

小林想发送一路音频，小周是否接收？双方有没有兼容的音频编码？这次连接要使用哪些传输和安全参数？这些信息都需要在发送声音前交给对方。

**信令**就是为建立、修改或结束会话而交换的控制信息。WebRTC 没有替应用规定统一的信令服务器和消息传输方式；应用可以通过自己的 HTTP、WebSocket 等机制交换信息。复制粘贴会话文本也在做信令，只是由人搬运消息。[^api]

WebRTC 常用 **SDP（Session Description Protocol，会话描述协议）** 承载会话说明。它是一种文本格式，里面描述媒体、格式和传输等参数。SDP 不包含等着播放的一段音频。下面是读它时需要认识的内容，不是一份可以直接导入的完整 SDP：[^sdp]

| 内容 | 此时需要回答的问题 |
| --- | --- |
| 音频媒体段、方向 | 这次有没有音频？本端准备发送、接收，还是双向通信？ |
| 编码格式及参数 | 双方准备用哪些兼容格式处理声音？ |
| ICE 参数 | 双方用哪组会话凭据，核对收到的检查请求是否属于这轮连接？ |
| 证书指纹 | 用证书内容计算出的短标识，核对后续安全握手提供的证书是否与描述一致 |
| 候选信息 | 有哪些可以尝试的传输地址？候选也可能通过后续消息单独交付 |

**Offer/Answer（提议／应答）** 组织这次协商：一端提出描述，另一端根据它给出自己的应答。Answer 需要遵守协商规则，不能把不兼容的任意配置当成“我同意了”。[^offer]

以 A 发起为例，先忽略候选到达的具体时间：

1. A 生成 Offer，并把它设置为自己的本地描述。
2. 应用将 Offer 交给 B；B 将它设置为远端描述。
3. B 生成 Answer，设置为自己的本地描述，再通过应用交给 A。
4. A 将收到的 Answer 设置为远端描述。

“本地”与“远端”是相对于当前这一端说的。同一份 A 的 Offer，在 A 是本地描述，在 B 是远端描述。浏览器需要知道两边的描述，才能按协商结果继续处理。

这几个步骤完成，说明描述已经按规则交给了两端。它还没有回答“描述里的哪条网络路径真正可达”。

## 路由器改了地址，外部看到的会是什么

先沿一份 UDP 数据走出家门。

小林的电脑从 `192.168.1.10:50000` 向外发送数据。家庭路由器可能把这份数据的源地址和端口改成外侧的 `198.51.100.10:62000`，并保存一份转换关系。外部响应到达这个外侧地址时，路由器才能按相应状态把数据交回内网。

这种地址转换叫 **NAT（Network Address Translation，网络地址转换）**。本例只画一层；真实路径可能存在多层转换，也可能使用不需要这类转换的 IPv6 路径。

**STUN（Session Traversal Utilities for NAT）** 提供一组消息机制。这里先使用其中的 Binding 请求／响应：A 向 STUN 服务器发请求，服务器在响应中告诉 A，它看到的源地址是什么。A 由此知道了“从这个服务器看过来”的映射地址。[^stun]

| 观察位置 | 本例看到的地址 |
| --- | --- |
| A 自己使用的本地端点 | `192.168.1.10:50000` |
| STUN 服务器看到的来源 | `198.51.100.10:62000` |
| A 发请求的 STUN 服务入口 | `192.0.2.10:3478` |

第三行是问路的服务地址；第二行才是本次观察得到的映射地址。不要把 STUN 服务器本身的地址填成 A 的媒体接收地址。

### 查到了映射，为什么仍可能收不到对方的数据

这里有两个容易混在一起的问题。

**映射行为**决定：A 向不同目的地发送时，外侧地址是否保持相同。某条实际路径可能让 A 发往 STUN 服务器时显示为 `198.51.100.10:62000`，发往 B 时却使用 `198.51.100.10:62004`。前一次查询不能保证后一条路径沿用原端口。

**过滤行为**决定：哪些外部来源的数据可以被放回来。即便映射保持不变，路由器或防火墙也可能允许 STUN 服务器的响应，却没有放行 B 发来的数据。[^nat]

因此，“收到了 STUN 响应”提供的是一次地址发现结果。它没有证明另一个用户能通过这个地址把数据发进来。只凭这一次结果，也不能完整判断整条网络路径的 NAT 行为。

## ICE 把可尝试地址变成一条经过检查的路径

A 可能有本地地址、外侧映射地址，还可能申请到中继地址。B 也有自己的选择。接下来要解决的事情是：拿哪些地址互相试，怎样确认结果，最终使用哪条路。

**ICE（Interactive Connectivity Establishment，交互式连接建立）** 负责收集、交换候选，进行连通性检查，并通过提名等过程确定要使用的候选对。它不是另一台专门收发所有声音的服务器。[^ice]

### 候选是一项尝试机会

**候选（candidate）** 是可供尝试的传输地址及其相关属性。先认识三种来源：

| 候选类型 | 怎样得到 | 只看它存在，能否证明已经连通 |
| --- | --- | --- |
| `host`，本地候选 | 来自本地网络接口对应的传输地址 | 不能。另一端可能不在可达的网络中 |
| `srflx`，服务器反射候选 | 通过服务器观察获知外侧映射地址 | 不能。还要检查对端路径 |
| `relay`，中继候选 | 向 TURN 服务申请分配，得到中继地址 | 不能。中继分配和后续路径也要能使用 |

浏览器有时会用 `.local` 结尾的 mDNS（Multicast DNS，组播域名系统）名称隐藏本地数字 IP 的直接展示。候选里没有出现熟悉的 `192.168.x.x`，不等于没有收集到本地候选。更完整的 ICE 中还有检查过程中发现的 `prflx`，即对端反射候选；基础实验先读前三种。[^mdns]

### 候选对需要真正检查

**候选对（candidate pair）** 把本端候选和远端候选放在一起，代表一条可检查的组合。协议、地址族等条件也要匹配，并不是把所有行不加区分地相乘就能使用。

ICE 使用带本轮凭据的 STUN 消息进行连通性检查。这时检查消息发向候选对所指向的对端路径，用来检查对方是否能按规则响应。它与前面“向 STUN 服务器询问映射地址”使用相关的消息机制，但目的不同。[^ice-check]

下面是一份**简化的教学记录**，没有展示重试计时、全部候选和内部状态字段：

| 已检查的候选对 | 本次结果 | 可以据此说什么 |
| --- | --- | --- |
| A 的 `host` ↔ B 的 `host` | 检查未成功 | 这次尝试没有建立这条路径 |
| A 的 `srflx` ↔ B 的 `srflx` | 检查超时 | 有映射地址仍未使这次检查成功；仅凭超时不能断言原因 |
| A 的 `relay` ↔ B 的 `srflx` | 检查成功，随后被提名并选中 | 这次连接选用包含 A 中继的路径 |

**检查成功**说明候选对通过了相应检查。可能存在多个检查成功的组合。ICE 还需要按协议标明准备使用哪一组，这一步叫提名；**被提名并选中**才说明它进入本次实际使用的选择。ICE 会按角色、优先级和协议过程处理它们，不能把“最早成功”“看起来 RTT 最低”直接当成所有实现的固定选路规则。[^nomination]

上表为了让结果易读而逐行排列。实际收集和检查可能交错进行，TURN 候选也可以在建立连接早期就准备好，不需要先等所有直连尝试宣告失败。

## TURN 参与的是数据转发

如果找不到可用直连路径，可以通过中继尝试通信。

**TURN（Traversal Using Relays around NAT）** 让客户端申请一个中继地址，由服务器按分配及权限等状态转发数据。本例中 A 主动联系服务入口 `192.0.2.30:3478`，申请得到 `192.0.2.30:55000`。后一个地址属于这次中继分配，不是所有客户端共用的固定媒体端口。[^turn]

若前面那组 `relay ↔ srflx` 被选中，A 发出的数据沿“ A → TURN → B ”走；返回数据沿“ B → TURN → A ”走。双方不必都使用 `relay` 候选才算经过 TURN：候选对中一端的中继已经改变了这条路径。

<figure class="interactive-diagram" style="margin:1.8rem 0;padding:1.3rem 0;border-top:1px solid var(--code-border);border-bottom:1px solid var(--code-border);container-type:inline-size">
    <iframe id="interactive-diagram-88d3e3007811d3cac0b4ea27e6519381-0" src="https://hex4c59.cc/articles/rtc-07-connection-setup/connection-paths.html" title="对照信令与实际数据路径：直连和 TURN 中继" width="100%" height="920" loading="lazy" sandbox="allow-scripts" style="display:block;width:100%;border:0;background:transparent;--figure-height:920px;--figure-mobile-height:1200px;--figure-compact-height:1040px"></iframe>
    <figcaption style="font-size:.78rem;line-height:1.8;margin-top:.7rem;color:var(--content-secondary)">对照信令与实际数据路径：直连和 TURN 中继 · <a href="https://hex4c59.cc/articles/rtc-07-connection-setup/connection-paths.html" target="_blank" rel="noopener">在独立窗口中查看</a></figcaption>
  </figure>


切换两种路径，观察中间的数据通路。上方的信令服务仍交换会话信息；切到 TURN 后，下方增加了实际承接数据的中继。STUN 地址发现没有画进持续数据通路，因为做过一次地址发现，不代表声音要不断经过那个 STUN 服务器。

使用 TURN 会消耗服务器转发带宽，也要求服务可达、凭据有效、分配及相关权限状态得到维护。它不能保证所有受限网络都能通。TURN 转发也不等于解码音频、混音或订阅多路媒体；处理这些任务的媒体服务器会在后续多人通信中讨论。

## 路通了，还要看安全处理和声音本身

选定路径之后，WebRTC 还需要完成安全处理。在媒体场景中，**DTLS（Datagram Transport Layer Security，数据报传输层安全）** 参与安全握手，并通过 DTLS-SRTP 机制导出媒体保护所需的密钥；**SRTP（Secure Real-time Transport Protocol，安全实时传输协议）** 保护 RTP 媒体的机密性和完整性等：加密媒体内容，并检查数据是否遭到改动。ICE 找到可用路径，不能代替这些处理。[^security]

SDP 中交换的证书指纹与后续握手验证有关。应用仍要保护信令、确认通信对象和房间权限；不能仅凭某次 DTLS 握手成功，就宣称登录身份和全部业务授权都已验证。TURN 本身只转发数据，也不会因为位于路径上就自动获得解密 SRTP 的密钥。[^security-arch]

即使路径和握手都已成功，麦克风也可能没采到数据，发送端可能没有加入音频轨道，接收端可能没有开始播放。浏览器中的 **MediaStreamTrack（媒体轨道）** 表示一路媒体源或远端媒体对象；收到远端轨道事件，也不能单独证明声音已经播放。

排查时，证据要跟着处理位置往后走：

| 已有证据 | 下一步检查 |
| --- | --- |
| 来电和接听消息成功 | 双方是否应用了对应的描述，候选是否交付 |
| 候选收集结束 | 连通性检查是否成功，实际选中了哪组候选 |
| ICE 已连接 | 安全握手是否成功，整体连接状态是否正常 |
| 连接已建立 | 是否存在有效发送轨道，音频 RTP 的发送／接收计数是否增长 |
| 接收音频数据正在增长 | 后续解码、输出设备、静音和播放策略是否允许声音出来 |

接收字节增长时要说明自己看的是什么计数。连接总字节里可能有检查和控制流量；音频 RTP 的接收增长比“网卡有流量”更接近问题，但也仍需核对实际输出。[^stats]

## 做一次本机实验：让两个连接传一条消息

先用一个不需要麦克风的小实验观察建立连接。打开配套页面，按“建立连接并发消息”：

<a href="https://hex4c59.cc/articles/rtc-07-connection-setup/ice-lab.html">打开本机 ICE 观察实验</a> · <a href="https://hex4c59.cc/articles/rtc-07-connection-setup/ice-lab.html" download="ice-lab.html">保存实验 HTML</a>

页面会在同一浏览器页面中创建 A、B 两个 `RTCPeerConnection` 对象。这个浏览器对象负责管理一次 WebRTC 连接。页面自动搬运 Offer 和 Answer，**页面里的代码在承担信令交换**，没有部署额外信令服务器。

实验使用 **RTCDataChannel（WebRTC 数据通道）** 发送文本 `rtc-hello`，收到后回传 `ack:rtc-hello`。它用于确认应用数据走通，本例没有音频轨道。数据通道用 SCTP（Stream Control Transmission Protocol，流控制传输协议）承载数据，外层由 DTLS 保护；前面媒体使用的 SRTP 不能直接套到这条文本消息上。[^data]

### 运行条件与范围

实验不配置外部 STUN 或 TURN，不访问麦克风、摄像头，不把描述和候选写入浏览器存储，也不显示完整候选地址。浏览器会执行本机 ICE 网络检查；这不等于“完全没有网络活动”。页面没有外部脚本、统计上报和 CDN 依赖。

可以直接在博客上打开。也可以把 HTML 下载到一个空目录，在该目录运行：

```sh
python3 -m http.server 8000 --bind 127.0.0.1
```

再用现代桌面浏览器打开 `http://127.0.0.1:8000/ice-lab.html`。命令需要 Python 3，作用只是提供本地静态页面，结束后按 Ctrl+C 关闭。不要把整个个人目录作为服务目录。若系统策略禁止 WebRTC 或本地检查，页面会给出错误；这个失败不等于所有公网 WebRTC 路径都失败。

### 页面做了哪些操作

为了让实验顺序容易核对，页面采用**等待本端候选收集结束，再交付完整描述**的办法：

1. 创建 A、B；A 创建数据通道，使协商中包含需要的数据传输。
2. A 创建并设置 Offer，等待 A 本轮候选收集结束。
3. 把 A 当前的本地描述交给 B，B 应用它。
4. B 创建并设置 Answer，等待 B 本轮收集结束，再交给 A。
5. 观察连接状态；数据通道打开后，A 发出文本，B 回传确认。
6. 读取统计中的已选候选对，显示两端候选类型。完成观察后，按“关闭并清理”。

实际应用常用 **Trickle ICE（增量交换 ICE 候选）**：候选一有结果就陆续交付，减少等待全部收集完成的时间。它改变候选交付时机，并没有省掉信令。候选还必须送到正确连接、正确的一轮协商中。[^trickle]

### 怎样读结果

先看事件顺序，再看连接快照。成功记录应包含 A/B 应用描述、通道打开、B 收到 `rtc-hello`、A 收到 `ack:rtc-hello`。最后一项能确认本次测试消息及其应用回传已经通过。

如果统计接口提供 `transport.selectedCandidatePairId`，页面会沿这个 ID 找到本端和远端候选，再显示 `host` 等类型。浏览器若没有提供对应字段，页面就显示“未提供”，不会从若干成功候选对中猜一个选中结果。

同机实验中观察到本地候选连接，只覆盖当前浏览器和本机环境。它不能验证两户家庭、企业网络或移动网络的公网直连，更不能验证 TURN，因为这里根本没有配置 TURN。不同浏览器可能暴露不同候选和统计字段，不要求输出地址、端口或候选数量完全一致。

2026 年 10 月 15 日，在 macOS 的 Codex 内置浏览器中运行成功，观察到消息与确认回传、`host ↔ host` 的已选候选对；关闭后连接对象已清理。这个结果说明本例数据通道可用，尚不能证明麦克风采集、音频编解码或扬声器播放成功。下一篇才把真正的媒体轨道接进双端实验。

## 换一段记录，自己判断

下面是另一组教学记录。先写下理由，再展开答案。

### 练习一：候选收集结束后，还缺什么

```text
A：Offer 已交给 B
B：Answer 已交给 A
A、B：iceGatheringState = complete
A：收集到 2 个 host、1 个 srflx
B：收集到 1 个 host、1 个 srflx
当前：没有任何候选对检查成功的记录
```

可以把界面改成“通话已建立”吗？能否据此说 A 的 NAT 一定属于某一种类型？

<details>
<summary>展开答案与判断依据</summary>

两项都不能。`iceGatheringState = complete` 表示当前收集阶段结束，候选类型和数量说明有这些可尝试项，没有提供候选对成功、选中、安全握手及媒体收发的证据。

`srflx` 的存在也没有完整描述映射与过滤行为。应继续查看候选是否正确交付、本轮凭据是否匹配、检查结果和实际网络路径。若把“收集结束”当成“连接结束”，回看“候选对需要真正检查”。

</details>

### 练习二：只有一端是 relay，数据经过哪里

```text
A 的已选本地候选：relay，192.0.2.30:55000
A 的已选远端候选：srflx，203.0.113.20:41000
对应候选对：已检查成功并选中
安全处理：本例媒体握手成功
```

A 发向 B 的媒体会经过 TURN 吗？B 返回 A 的媒体呢？这能证明 TURN 已解码声音吗？

<details>
<summary>展开答案与路径</summary>

两个方向都经过 A 的中继。逻辑路径分别是 A → TURN → B 和 B → TURN → A。B 返回时发送到 A 的中继地址，TURN 再交付给 A；不要求 B 自己也申请中继。

这不能证明 TURN 解码了声音。普通 TURN 转发与媒体解码是不同任务，媒体保护的密钥也不会仅因转发而交给 TURN。若把 `relay` 当成“双方都必须用的模式”，回看图中的中继路径。

</details>

### 练习三：消息传通了，为什么仍不能证明能听见声音

```text
ICE：已连接
DataChannel：open
B 收到：rtc-hello
A 收到：ack:rtc-hello
音频轨道：0 条
```

这些记录证明了什么？若要验证语音，还需补哪些证据？

<details>
<summary>展开答案与检查顺序</summary>

它们证明这次数据通道成功传输了测试消息，并完成应用回传。没有音频轨道，当然不能据此确认声音。

语音实验需要加入有效音频轨道，检查音频发送和接收计数、后续解码与实际播放，并记录设备和权限状态。即便先收到了远端轨道对象，也要继续验证内容是否传来、是否输出。若直接把 `open` 当成“能听见”，回看“路通了，还要看安全处理和声音本身”。

</details>

建立连接之后，前面学过的时间约束才有了承载它们的实际路径。接下来的双端实验会沿同一条顺序核对：交换描述、选中路径、安全处理、媒体收发，最后确认实际输出。

[回看第六篇：怎样从收发记录看出延迟在增长](https://hex4c59.cc/articles/rtc-06-delay-trend/) · [系列目录](https://hex4c59.cc/articles/rtc-from-zero/)

## 参考资料

下列 W3C 规范于 2026 年 10 月 15 日核对；实验展示字段以运行时浏览器实际提供的结果为准。

[^addresses]: [RFC 1918：私有地址](https://www.rfc-editor.org/rfc/rfc1918.html#section-3)；[RFC 5737：文档示例 IPv4 地址](https://www.rfc-editor.org/rfc/rfc5737.html#section-3)。
[^api]: [W3C WebRTC：Introduction](https://www.w3.org/TR/webrtc/#introduction) 与 [RTCPeerConnection 接口](https://www.w3.org/TR/webrtc/#rtcpeerconnection-interface)，包括描述、候选、状态与轨道处理。
[^sdp]: [RFC 8866 §5：SDP 描述格式](https://www.rfc-editor.org/rfc/rfc8866.html#section-5)；[RFC 8839：SDP 中的 ICE 使用](https://www.rfc-editor.org/rfc/rfc8839.html)。
[^offer]: [RFC 3264 §5—6：生成 Offer 与 Answer](https://www.rfc-editor.org/rfc/rfc3264.html#section-5)。
[^stun]: [RFC 8489 §7、§14.2：Binding 与映射地址](https://www.rfc-editor.org/rfc/rfc8489.html#section-7)，2020 年 2 月发布；其摘要也明确说明 STUN 本身不是完整的 NAT 穿越方案。
[^nat]: [RFC 4787 §4.1、§5：NAT 映射与过滤](https://www.rfc-editor.org/rfc/rfc4787.html#section-4.1)，2007 年 1 月发布。它给出行为分类和要求，不能据此假设所有实际设备都符合要求。
[^ice]: [RFC 8445 §2、§5—8：ICE 概览、收集、检查与结束处理](https://www.rfc-editor.org/rfc/rfc8445.html#section-2)，2018 年 7 月发布。
[^ice-check]: [RFC 8445 §7：ICE 连通性检查](https://www.rfc-editor.org/rfc/rfc8445.html#section-7)。
[^nomination]: [RFC 8445 §8.1.1：候选对提名](https://www.rfc-editor.org/rfc/rfc8445.html#section-8.1.1)。
[^mdns]: [RFC 8828：WebRTC IP 地址处理](https://www.rfc-editor.org/rfc/rfc8828.html)；[W3C WebRTC：隐私与本地网络地址](https://www.w3.org/TR/webrtc/#revealing-ip-addresses)，说明候选暴露与隐私边界。mDNS 方案的背景见 [Using Multicast DNS to protect privacy when exposing ICE candidates](https://datatracker.ietf.org/doc/html/draft-ietf-mmusic-mdns-ice-candidates-03)（2021 年 12 月 6 日草案，已过期，非 RFC）。`prflx` 的发现见 RFC 8445 §7。
[^turn]: [RFC 8656 §3：TURN 操作概览](https://www.rfc-editor.org/rfc/rfc8656.html#section-3)，2020 年 2 月发布，区分服务端地址、分配得到的中继地址与相关状态。
[^security]: [RFC 5764 §4：DTLS-SRTP](https://www.rfc-editor.org/rfc/rfc5764.html#section-4)；[RFC 3711 §3：SRTP](https://www.rfc-editor.org/rfc/rfc3711.html#section-3)。
[^security-arch]: [RFC 8827 §6：WebRTC 安全架构](https://www.rfc-editor.org/rfc/rfc8827.html#section-6)；[RFC 8656 §21：TURN 安全考虑](https://www.rfc-editor.org/rfc/rfc8656.html#section-21)。
[^stats]: [W3C WebRTC Statistics：transport](https://www.w3.org/TR/webrtc-stats/#transportstats-dict*)、[候选对](https://www.w3.org/TR/webrtc-stats/#candidatepair-dict*) 与 [入站 RTP](https://www.w3.org/TR/webrtc-stats/#inboundrtpstats-dict*)。实验只按统计对象之间的 ID 引用读取已选路径。
[^data]: [RFC 8831 §5：WebRTC 数据通道传输](https://www.rfc-editor.org/rfc/rfc8831.html#section-5)，2021 年 1 月发布。
[^trickle]: [RFC 8838 §1、§9：Trickle ICE 与增量交付](https://www.rfc-editor.org/rfc/rfc8838.html#section-9)，2021 年 1 月发布。

