一、数据通道是什么?先别急着写代码
WebRTC 数据通道,说白了就是浏览器之间的一条「隐形网线」。
它不经过服务器中转,直接在两个浏览器之间传数据。我刚开始接触时也觉得神奇——两个网页居然能直接对话?
嗯,确实可以。而且它用的是 SCTP 协议,不是传统的 TCP 或 UDP。你想想看,这意味着什么?
- 可靠传输:默认情况下,数据不会丢,顺序也不会乱
- 低延迟:没有服务器中转,数据直达
- 安全加密:DTLS 加密,跟 HTTPS 一个级别
我个人习惯把数据通道比作「WebSocket 的升级版」。WebSocket 还要连服务器,数据通道直接点对点。
二、创建数据通道:就这么简单
创建数据通道,只需要一行代码。真的,就一行。
const dataChannel = peerConnection.createDataChannel('myLabel');
这里的 'myLabel' 是通道名称。你可以随便起名,但两端要约定好。
我记得第一次写的时候,以为还要配置什么参数。其实默认就够用了。当然,你也可以传第二个参数:
const dc = pc.createDataChannel('chat', {
ordered: true, // 保证顺序
maxRetransmits: 3 // 最多重传3次
});
这里有个小坑:maxRetransmits 和 maxPacketLifeTime 不能同时设置。我当初踩过这个坑,两个都设了,结果浏览器直接报错。
maxRetransmits,实时游戏用 maxPacketLifeTime。前者保证送达,后者保证时效。
三、监听事件:通道的「心跳」
数据通道有四个核心事件。我按使用频率排个序:
| 事件 | 触发时机 | 我常用的场景 |
|---|---|---|
open |
通道建立成功 | 显示「连接成功」提示 |
message |
收到对方数据 | 处理聊天消息或文件 |
close |
通道关闭 | 清理资源、显示断开提示 |
error |
发生错误 | 日志记录、重连逻辑 |
代码怎么写?看这里:
dataChannel.onopen = () => {
console.log('通道已打开');
// 可以开始发消息了
};
dataChannel.onclose = () => {
console.log('通道已关闭');
// 清理工作
};
dataChannel.onerror = (err) => {
console.error('通道错误:', err);
};
dataChannel.onmessage = (event) => {
console.log('收到消息:', event.data);
};
为什么 open 事件这么重要?因为通道没打开之前,你发消息是发不出去的。我曾经在项目里犯过这个错——通道还没 ready 就发数据,结果消息全丢了。
open 事件触发后再发消息。可以用一个标志位控制:let isOpen = false;,在 onopen 里设为 true。
四、发送文本消息:实战演练
发送消息用 send() 方法。就这么简单:
dataChannel.send('你好,世界!');
但要注意,send() 只能传字符串、Blob、ArrayBuffer 或 ArrayBufferView。传对象?不行,得先 JSON 序列化:
const msg = {
type: 'chat',
content: '你好',
timestamp: Date.now()
};
dataChannel.send(JSON.stringify(msg));
接收端再解析回来:
dataChannel.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log(data.type, data.content);
};
我习惯在消息里加一个 type 字段。这样后期扩展功能(比如文件传输、信令交互)就方便多了。
五、完整示例:一个迷你聊天室
把上面所有知识点串起来,就是一个最简单的聊天功能:
// 创建连接
const pc = new RTCPeerConnection();
const dc = pc.createDataChannel('chat');
let isChannelReady = false;
dc.onopen = () => {
isChannelReady = true;
console.log('✅ 通道已就绪');
};
dc.onmessage = (event) => {
console.log('💬 收到:', event.data);
};
// 发送消息
function sendMessage(text) {
if (!isChannelReady) {
console.warn('⚠️ 通道还没准备好');
return;
}
dc.send(text);
}
// 使用
sendMessage('Hello WebRTC!');
这段代码虽然简单,但已经覆盖了数据通道的核心流程:创建 → 监听 → 发送。
六、知识体系总览
下面这张图总结了本章的核心逻辑。我画的时候特意把「连接建立」放在最前面——这是所有操作的前提。
七、常见问题与避坑
最后分享几个我实际项目中遇到的坑:
- 通道未打开就 send:消息会静默丢失。解决方案:用
readyState检查状态。 - 两端同时 createDataChannel:会导致通道重复。建议一端创建,另一端在
ondatachannel里接收。 - 消息太大:SCTP 有消息大小限制(通常 16KB-64KB)。大文件要分片发送。
dataChannel.readyState 查看当前状态。它有三个值:connecting、open、closing、closed。
好了,数据通道入门就到这里。代码不多,但每个细节都值得你亲手敲一遍。下次我们聊聊如何传输二进制数据——文件、图片、视频片段,都能走数据通道。