5月28日 02:13
WebRTC的数据通道有什么作用?如何使用它传输非媒体数据?
WebRTC 数据通道(Data Channel)是 WebRTC 中与媒体通道并列的传输机制,基于 SCTP over DTLS 协议栈,在浏览器之间建立加密的点对点连接来传输任意二进制或文本数据。
数据通道的核心作用
与媒体通道的区别:媒体通道使用 SRTP 传输音视频,而数据通道使用 SCTP over DTLS 传输非媒体数据。两者共享同一个 ICE 传输层,但走不同的协议栈,互不干扰。
相比 WebSocket 的优势:WebSocket 需要服务器中继,数据经由服务端转发;数据通道建立后直接在两端之间传输,省去服务器中转的延迟和带宽开销。API 设计上与 WebSocket 高度相似,降低了学习成本。
关键特性:
- DTLS 加密:所有数据自动经过 DTLS 加密,无需应用层额外处理
- 全双工通信:双方可同时收发,不存在方向限制
- 可靠性可配置:通过
ordered、maxRetransmits、maxPacketLifeTime三个参数,可在可靠有序(类 TCP)和不可靠无序(类 UDP)之间自由选择 - NAT 穿透:复用 ICE 框架的 NAT 穿透能力,无需额外处理
数据通道的协议栈
理解协议栈有助于在面试中讲清"为什么数据通道既能可靠传输又能低延迟":
shell应用层数据 ↓ SCTP(流控传输协议,提供多流、可靠/部分可靠传输) ↓ DTLS(加密层,提供安全性) ↓ UDP(ICE 协商后的 P2P 通道)
SCTP 支持在同一关联上建立多个流(Stream),每个数据通道对应一个 SCTP 流,通道间互不阻塞。SCTP 的"部分可靠"扩展(PR-SCTP)使得配置 maxRetransmits 和 maxPacketLifeTime 成为可能,这是数据通道灵活性的根源。
创建数据通道
javascriptconst 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 模式(不可靠无序)maxRetransmits和maxPacketLifeTime互斥,只能设一个
监听事件与收发数据
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('收到你的消息'); }; };
发送数据的三种格式:
javascriptchannel.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),接收方 onmessage 的 event.data 会自动还原为 string 或 ArrayBuffer。
缓冲区管理与背压
数据通道有发送缓冲区,持续发送大量数据而不检查缓冲区会导致内存暴涨甚至通道崩溃:
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 的协商开销。