本篇是 WebRTC 101 系列 第 5 篇,讲
RTCDataChannel:不靠音视频、纯跑任意数据的点对点通道,以及它和 WebSocket 到底怎么选。
RTCDataChannel:SCTP over DTLS,什么时候该用它
前面的篇章都在讲音视频;但 WebRTC 里还有一条"不搞媒体也能用"的通道——数据通道。它是做游戏状态同步、文件传输、白板协作、以及先用文本协议握手再升级音视频这类场景的关键。
1. 它底层是什么
一句话:DataChannel = 跑在 WebRTC 加密传输之上的 SCTP 流。
- **SCTP(流控制传输协议)**是它真正的载体(RFC 8831/8832),而 SCTP 本身又是 over DTLS(RFC 8261)——和第 4 篇媒体共用同一条 DTLS 隧道。
- 因为搭在 WebRTC 已经打通的通道上,它天然继承了:P2P 路径、端到端加密、ICE 打洞后的可达性。
- 对应用而言,它暴露成像 WebSocket 一样的 API(
onopen/onmessage/send()/close()),但能力比 WebSocket 强的地方在于——你可以选择可靠性策略。
2. 关键选项:不只是"可靠或不可靠"
创建通道时(createDataChannel(label, options))可定以下参数,创建后不可改:
| 选项 | 含义 | 默认 |
|---|---|---|
ordered | 是否保证按序到达 | true |
maxRetransmits | 最多重传次数(丢了就放弃) | 无限制 |
maxPacketLifeTime | 数据最多存活毫秒(超时就丢) | 无限制 |
protocol | 应用自定义子协议名 | "" |
negotiated / id | 预协商通道:两端各自用同一个 id 创建 | 自动协商 |
可靠性谱系(记住这个就够用):
完全可靠 + 有序 ← 默认,类似可靠流(传文件、同步状态)
部分可靠 + 有序 ← maxRetransmits / maxPacketLifeTime(限重传/限时,控制实时性)
乱序 + 部分可靠 ← ordered:false(游戏快照、实时位置,最新优先、旧了直接丢)
注意语义坑:maxRetransmits 与 maxPacketLifeTime 二选一,不能同时设。做"丢包不补、过期作废"的实时消息(比如打字光标、游戏移动),选乱序 + 短 TTL,延迟最可控。
3. 最简可用片段(连接建立后)
// 发起方(offerer 通常负责建通道)
const dc = pc.createDataChannel("chat", { ordered: true });
// 对端在连接建立后收到
pc.ondatachannel = (event) => {
const dc = event.channel;
dc.onopen = () => dc.send("hi");
dc.onmessage = (e) => console.log("got:", e.data);
};
两个容易犯的错:
- 通道要在连接建立前创建:
createDataChannel应在offer/answer之前调用,这样它的协商才会出现在 SDP 里(你会在 SDP 看到一个m=application … SCTP段——这就是数据通道); - 对端不是"主动创建":对端通过
ondatachannel拿到通道,而不是再调一次createDataChannel(除非用了negotiated: true+ 相同id)。
4. 背压:别把内存写爆
send() 是异步排队的,如果一直发而对方消化慢,bufferedAmount 会涨,最终爆内存。处理方式与 WebSocket 一致:
if (dc.bufferedAmount > 阈值) { 稍等; } // 简单节流
dc.onbufferedamountlow = () => 继续发; // 或监听 low 水位再继续
传大文件尤其要分块 + 看 bufferedAmount:每块设成可管理大小(几 KB~几百 KB),发完等 bufferedamountlow 再发下一块,才能跑满又不炸。
5. DataChannel vs WebSocket(选型表)
两者 API 几乎一样,但底层哲学不同:
| 维度 | WebSocket | RTCDataChannel |
|---|---|---|
| 拓扑 | 客户端 ⇄ 服务器(长连接) | 端到端 P2P(可直连,必要时 TURN) |
| 承载 | TCP | SCTP over DTLS(基于已建好的 WebRTC 通道) |
| 是否过你的服务器 | 是(瓶颈/成本在服务器) | 直连时不过;走 TURN 时才过中继 |
| 可靠性选项 | 只有可靠 + 有序 | 可选乱序 / 限重传 / 限时 |
| 延迟 | 好 | 更好(少一跳,且可放弃旧数据) |
| 前置条件 | 只要连服务器 | 要先信令 + ICE 打通(复杂些) |
| 加密 | TLS(客户端-服务器) | DTLS(端到端) |
| 穿越代理/NAT | 友好(TCP 80/443) | 依赖 STUN/TURN(UDP 常被墙) |
怎么选的一句话:
对方必然是你的服务器、或想要 HTTP 友好好穿透 → 用 WebSocket; 目标是两台对等端直接说话、或需要"最新优先可丢旧"的实时语义、或不想让数据都过你的服务器 → 用 DataChannel(先接受它的信令+ICE 复杂度)。
常见 combo:WebSocket 只做信令/房间,建好 PeerConnection 后,真正的业务数据(位置、白板、控制消息)走 DataChannel——许多实时应用就是这样分工的。
6. 使用场景速查
- 文本/二进制消息:聊天、协作光标、游戏指令(延迟敏感用乱序+TTL);
- 文件/流:P2P 传文件(无需服务器中转,第 0 篇提过 WebTorrent 即此类);
- 与音视频并存:先 DataChannel 协商房间参数,再打开媒体;
- 私有信令的备选:两个已建立会话的端再聊,不需要再经服务器。