# DataChannelController 与数据通道 · 传任意数据

> WebRTC 不止传音视频，还能传任意数据——文件、游戏状态、聊天消息。这一章读 pc/data_channel_controller.cc：数据通道的控制面，SctpDataChannel 如何架在 SCTP-over-DTLS 之上，以及可靠性/有序性怎么配置。SCTP 协议本身留到第 8 部分深挖。

- 作者：David（道雾轩）
- 专栏：音视频与 WebRTC 详解（https://daiw.org/manual/webrtc.md）
- 最后更新：2026-07-14
- 原文：https://daiw.org/manual/webrtc/data-channel-controller
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# DataChannelController 与数据通道 · 传任意数据

WebRTC 的名气在音视频，但它还有一条常被低估的能力：**数据通道（DataChannel）**——在两个端点间传**任意数据**，文件、游戏同步、聊天、信令二次通道，都行。管理它的，是 [`PeerConnection` 的 `data_channel_controller_` 成员](https://daiw.org/manual/webrtc/peer-connection-object)。这一章读它的**控制面**；SCTP 协议本身的硬核细节，留给[第 8 部分](https://daiw.org/manual/webrtc/source-map)。

## 数据通道站在哪一层

先定位。数据通道**不走 [RTP](https://daiw.org/manual/webrtc/source-map)**（RTP 是给实时音视频的），而是走 **SCTP**，再套在 [DTLS](https://daiw.org/manual/webrtc/source-map) 上：

```text
DataChannel(应用 API)
   └── SCTP(可靠/有序可调,第 8 部分)
         └── DTLS(加密,第 3 部分)
               └── ICE 选定的通路(第 2 部分)
```

和音视频一样，它也**复用[同一条底层传输](https://daiw.org/manual/webrtc/jsep-transport-controller)**（BUNDLE 时），只是上层协议从 RTP 换成了 SCTP。SDP 里，它对应一条**应用类型的 m-line**（`m=application ... webrtc-datachannel`）。

## DataChannelController：控制面

`pc/data_channel_controller.cc` 里的 `DataChannelController`，管理这一切。它的声明就点明了身份（`pc/data_channel_controller.h`）：

```cpp
// pc/data_channel_controller.h(节选)
class DataChannelController : public SctpDataChannelControllerInterface, ... {
  // 创建一个数据通道(带 proxy,保证线程安全)
  ... InternalCreateDataChannelWithProxy(absl::string_view label, ...);
  void OnChannelStateChanged(SctpDataChannel* channel, ...);
  // 持有到 SCTP 传输的连接:DataChannelTransportInterface*
};
```

- 它实现 `SctpDataChannelControllerInterface`——是各个 `SctpDataChannel` 的**大管家**。
- `CreateDataChannel`（API 层）最终走到 `InternalCreateDataChannelWithProxy`，造出一个 `SctpDataChannel` 并[包上代理](https://daiw.org/manual/webrtc/proxy-pattern)。
- 它持有一个 `DataChannelTransportInterface*`——通往底层 [SCTP 传输](https://daiw.org/manual/webrtc/source-map)的出口。
- 通道状态变化（打开、关闭）通过 `OnChannelStateChanged` 回上来，再通知应用。

## SctpDataChannel：一条通道

每条数据通道是一个 **`SctpDataChannel`**（`pc/sctp_data_channel.cc`）。它是应用直接打交道的对象：`send()` 发数据、`onmessage` 收数据、`onopen`/`onclose` 感知状态。多条数据通道**复用同一个 SCTP association**（[第 8 部分](https://daiw.org/manual/webrtc/source-map)），靠 SCTP 的**流（stream）id** 区分——就像 [BUNDLE 靠 SSRC 区分媒体](https://daiw.org/manual/webrtc/jsep-transport-controller)，SCTP 靠 stream id 区分通道。

## 可靠性与有序性：可调

数据通道最迷人的地方，是它的**传输语义可配**——这也是它比「裸 UDP」或「裸 TCP」都灵活的原因：

<Callout type="info">
  **数据通道的可靠性和有序性，创建时可调——这继承自底层 [SCTP](https://daiw.org/manual/webrtc/source-map) 的能力。** 两个旋钮：

  - **有序 vs 无序（`ordered`）**：要不要保证「先发的先到」。聊天消息要有序；而实时游戏状态可能宁可乱序也要低延迟。
  - **可靠性（`maxRetransmits` / `maxPacketLifeTime`）**：丢了要不要重传、重传几次 / 多久内有效。设成「完全可靠」就像 TCP（必达）；设成「最多重传 0 次」就像 UDP（尽力而为）；还能取**中间态**——「最多重传 3 次」或「50ms 内才重传」。

  这种「部分可靠（partial reliability）」正是 [SCTP 相对 TCP 的杀手锏](https://daiw.org/manual/webrtc/source-map)（RFC 3758，第 8 部分细讲）：**你按数据的性质，精确选择「多可靠」**。一条通道可以完全可靠有序（传文件），另一条可以不可靠无序（传实时位置），它们复用同一个 association。`DataChannelController` 把应用设的这些参数，翻译成对 SCTP 传输的配置。
</Callout>

```mermaid
flowchart TD
    APP["应用:createDataChannel('chat')"] --> DCC["DataChannelController<br/>InternalCreateDataChannelWithProxy"]
    DCC --> CH1["SctpDataChannel 'chat'(stream 1,有序可靠)"]
    DCC --> CH2["SctpDataChannel 'game'(stream 3,无序不可靠)"]
    CH1 --> SCTP["SCTP association(第 8 部分)"]
    CH2 --> SCTP
    SCTP --> DTLS["DTLS(第 3 部分)→ ICE 通路"]
```

## 小结与下一章

**数据通道**让 WebRTC 传任意数据，走 **SCTP-over-DTLS**（不走 RTP），对应 SDP 一条 `application` m-line，BUNDLE 时复用[同一条底层传输](https://daiw.org/manual/webrtc/jsep-transport-controller)。[`data_channel_controller_`](https://daiw.org/manual/webrtc/peer-connection-object) 即 `DataChannelController` 是控制面大管家：`InternalCreateDataChannelWithProxy` 造出 `SctpDataChannel`（多条通道靠 SCTP **stream id** 区分），并把应用设的**有序性 / 可靠性**（有序？重传几次？）翻译成 SCTP 配置——**部分可靠**是它相对 TCP/UDP 的独特优势。SCTP 协议本身见[第 8 部分](https://daiw.org/manual/webrtc/source-map)。

会话建立的最后一块拼图，是**统计**——`getStats()` 怎么从散落在[各个线程各个对象](https://daiw.org/manual/webrtc/threading-model)里的数据，汇总成一份报告。下一章读 `RtcStatsCollector`，收尾第 1 部分。👉 [RtcStatsCollector：统计怎么汇总](https://daiw.org/manual/webrtc/stats-collector)。

## 参考资料

- [1] libwebrtc 源码.`pc/data_channel_controller.h` / `.cc`（`DataChannelController`、`InternalCreateDataChannelWithProxy`）。
- [2] libwebrtc 源码.`pc/sctp_data_channel.h` / `.cc`（`SctpDataChannel`）。
- [3] IETF RFC 8831「WebRTC Data Channels」、RFC 8832「Data Channel Establishment Protocol」。
