5月28日 02:13

WebRTC的数据通道有什么作用?如何使用它传输非媒体数据?

WebRTC 数据通道(Data Channel)是 WebRTC 中与媒体通道并列的传输机制,基于 SCTP over DTLS 协议栈,在浏览器之间建立加密的点对点连接来传输任意二进制或文本数据。

数据通道的核心作用

与媒体通道的区别:媒体通道使用 SRTP 传输音视频,而数据通道使用 SCTP over DTLS 传输非媒体数据。两者共享同一个 ICE 传输层,但走不同的协议栈,互不干扰。

相比 WebSocket 的优势:WebSocket 需要服务器中继,数据经由服务端转发;数据通道建立后直接在两端之间传输,省去服务器中转的延迟和带宽开销。API 设计上与 WebSocket 高度相似,降低了学习成本。

关键特性

  • DTLS 加密:所有数据自动经过 DTLS 加密,无需应用层额外处理
  • 全双工通信:双方可同时收发,不存在方向限制
  • 可靠性可配置:通过 orderedmaxRetransmitsmaxPacketLifeTime 三个参数,可在可靠有序(类 TCP)和不可靠无序(类 UDP)之间自由选择
  • NAT 穿透:复用 ICE 框架的 NAT 穿透能力,无需额外处理

数据通道的协议栈

理解协议栈有助于在面试中讲清"为什么数据通道既能可靠传输又能低延迟":

shell
应用层数据 SCTP(流控传输协议,提供多流、可靠/部分可靠传输) DTLS(加密层,提供安全性) UDP(ICE 协商后的 P2P 通道)

SCTP 支持在同一关联上建立多个流(Stream),每个数据通道对应一个 SCTP 流,通道间互不阻塞。SCTP 的"部分可靠"扩展(PR-SCTP)使得配置 maxRetransmitsmaxPacketLifeTime 成为可能,这是数据通道灵活性的根源。

创建数据通道

javascript
const pc = new RTCPeerConnection(config); // 创建方(Offerer)主动创建 const channel = pc.createDataChannel('chat', { ordered: true, // 保证消息有序到达 maxRetransmits: 3, // 最多重传3次,超出则丢弃 // maxPacketLifeTime: 3000, // 与maxRetransmits二选一,消息最大存活时间(ms) protocol: 'text', // 子协议标识 negotiated: false, // false=自动协商,true=手动指定id });

参数说明

  • ordered: true + maxRetransmits: null + maxPacketLifeTime: null = TCP 模式(可靠有序)
  • ordered: false + maxRetransmits: 0 = UDP 模式(不可靠无序)
  • maxRetransmitsmaxPacketLifeTime 互斥,只能设一个

监听事件与收发数据

javascript
// 发送方 channel.onopen = () => { // 通道就绪后才能发送 channel.send('Hello!'); }; channel.onmessage = (e) => { console.log('收到:', e.data); }; channel.onclose = () => { console.log('通道关闭'); }; // 接收方(被动方通过 ondatachannel 获取) pc.ondatachannel = (e) => { const rc = e.channel; rc.onmessage = (ev) => { console.log('收到:', ev.data); }; rc.onopen = () => { rc.send('收到你的消息'); }; };

发送数据的三种格式

javascript
channel.send('字符串'); // string → PPID 51 channel.send(new ArrayBuffer(8)); // binary → PPID 53 channel.send(new Blob(['data'])); // binary → PPID 53

SCTP 内部通过 PPID(Payload Protocol Identifier)区分 UTF-8 文本(51)和二进制数据(53),接收方 onmessageevent.data 会自动还原为 stringArrayBuffer

缓冲区管理与背压

数据通道有发送缓冲区,持续发送大量数据而不检查缓冲区会导致内存暴涨甚至通道崩溃:

javascript
// 检查缓冲区是否快满 if (channel.bufferedAmount > channel.bufferedAmountLowThreshold) { // 暂停发送,等待缓冲区排空 channel.onbufferedamountlow = () => { // 恢复发送 sendNextChunk(); }; return; } channel.send(chunk);

bufferedAmountLowThreshold 默认为 0,建议设为缓冲区容量的 1/4 左右。这是面试中常被追问的实战细节。

常见应用场景

场景配置建议原因
实时游戏状态同步ordered: false, maxRetransmits: 0旧状态无需重传,只要最新帧
协作白板ordered: true, maxRetransmits: 3操作顺序不能乱,但偶尔丢帧可接受
文件传输ordered: true(默认可靠模式)文件必须完整到达
聊天消息ordered: true(默认可靠模式)消息不能丢、不能乱序
IoT 传感器数据ordered: false, maxPacketLifeTime: 1000传感器数据实时性优先

面试追问方向

  • 数据通道能传多大消息? 理论上 SCTP 支持最大 1 GiB 的消息(通过分片重组),但实际受浏览器实现限制,建议单条消息不超过 64 KiB,大文件应分块传输。
  • 数据通道和 WebSocket 怎么选? 需要服务器中转或一对多广播用 WebSocket;需要点对点低延迟且能接受 ICE 协商开销用数据通道。两者也可以混合使用。
  • negotiated: true 是什么? 跳过 DCEP 协商,双方通过约定相同的 id 手动创建通道,减少一次 RTT 的协商开销。
标签:WebRTC