1. WebRTC基础回顾:实时通信的核心原理、三大API与信令服务器
各位同学,欢迎来到《WebRTC性能优化大师课》的第一章。
说实话,我见过太多人一上来就扎进代码里,结果连WebRTC为什么能「实时」都没搞明白。我自己刚接触时也踩过这个坑——调了一周的视频卡顿,最后发现是信令流程写错了。嗯,这节课我们就从根上把这些东西捋清楚。
1.1 实时通信的核心原理:到底「实时」在哪?
WebRTC的全称是Web Real-Time Communication。说白了,就是让浏览器之间能直接传音视频和数据,不需要中间服务器转发。
你想想看,传统的视频通话,数据要先到服务器,再转发给对方。这中间至少多走了一跳,延迟自然就上去了。WebRTC走的是P2P(点对点)路线,浏览器A直接连浏览器B。
但这里有个问题:A和B怎么找到对方?它们各自在局域网里,IP地址是私有的。这就引出了两个关键技术:
- NAT穿透(ICE框架):通过STUN/TURN服务器,帮双方找到对方的公网地址。
- SDP协商:双方交换各自的媒体能力(支持什么编码、分辨率、带宽等)。
我在项目中遇到过最头疼的情况:明明STUN服务器配置对了,但就是连不上。后来发现是防火墙把UDP端口封了。所以,TURN服务器作为中继兜底,是生产环境必须准备的。
1.2 三大API:WebRTC的「三驾马车」
WebRTC暴露给开发者的核心API就三个。我习惯把它们比作「采集-传输-数据」三条线。
1.2.1 getUserMedia:采集音视频
这个API负责打开摄像头和麦克风。代码很简单:
navigator.mediaDevices.getUserMedia({
video: true,
audio: true
}).then(stream => {
// stream 就是本地视频流
localVideo.srcObject = stream;
}).catch(err => {
console.error('摄像头被拒绝:', err);
});
这里有个细节:video: true 默认使用前置摄像头。如果你想指定后置,可以传 facingMode: { exact: 'environment' }。
1.2.2 RTCPeerConnection:建立P2P连接
这是WebRTC最核心的API。它负责ICE协商、媒体流传输、带宽自适应等所有底层工作。
const pc = new RTCPeerConnection({
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{ urls: 'turn:your-turn-server.com', credential: 'password' }
]
});
// 添加本地流
localStream.getTracks().forEach(track => {
pc.addTrack(track, localStream);
});
// 监听远程流
pc.ontrack = event => {
remoteVideo.srcObject = event.streams[0];
};
// 创建Offer
pc.createOffer().then(offer => pc.setLocalDescription(offer));
你想想看,这个API背后做了多少事:
- 收集所有可能的网络候选(本地IP、公网IP、中继地址)
- 与远端交换SDP
- 选择最优路径建立连接
- 实时监控网络质量,动态调整码率
1.2.3 RTCDataChannel:传数据,不传媒体
很多人以为WebRTC只能传视频。其实它还能传任意二进制数据。RTCDataChannel就是干这个的。
const dc = pc.createDataChannel('myChannel', {
ordered: false, // 允许乱序到达,提高速度
maxRetransmits: 0 // 不重传,丢包就丢
});
dc.onopen = () => {
dc.send('Hello from peer A!');
};
dc.onmessage = event => {
console.log('收到:', event.data);
};
我在做文件传输工具时,就用了DataChannel。它的延迟比WebSocket低得多,因为走的是P2P路径。但要注意:DataChannel的可靠性取决于你设置的参数。如果你需要100%可靠,就设 ordered: true 和 maxRetransmits: -1。
1.3 信令服务器的作用与搭建
前面说了,WebRTC是P2P的。但建立连接之前,双方需要交换一些「元数据」——比如SDP和ICE候选。这个交换过程,就叫信令。
信令服务器本质上就是一个消息中转站。它不参与媒体流传输,只负责传递控制信息。
- 房间管理:谁在哪个房间,谁要和谁连
- 消息转发:把A的Offer转发给B,把B的Answer转发给A
- ICE候选交换:把A的ICE候选发给B,反之亦然
最简单的信令服务器,用Node.js+WebSocket就能搭:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
const rooms = {};
wss.on('connection', ws => {
ws.on('message', message => {
const data = JSON.parse(message);
if (data.type === 'join') {
// 加入房间
if (!rooms[data.room]) rooms[data.room] = [];
rooms[data.room].push(ws);
} else if (data.type === 'offer' || data.type === 'answer' || data.type === 'candidate') {
// 转发给房间内其他成员
rooms[data.room].forEach(client => {
if (client !== ws) {
client.send(JSON.stringify(data));
}
});
}
});
});
这个例子只有30行代码,但已经能跑通一个基本的信令流程了。当然,生产环境还需要考虑:
- 用户认证(谁是谁)
- 房间容量限制
- 断线重连时的状态恢复
1.4 本章知识体系总览
下面这张图,把WebRTC的核心流程串起来了。我建议你多看几遍,理解每一步的先后顺序。
从这张图你能看到:信令服务器只在连接建立前起作用。一旦P2P通道打通,媒体流和数据就直接在浏览器之间传输了。这也是WebRTC低延迟的根本原因。
1.5 本章小结
好,我们快速回顾一下这节课的核心:
- 实时通信的核心:P2P直连 + NAT穿透 + SDP协商
- 三大API:getUserMedia(采集)、RTCPeerConnection(传输)、RTCDataChannel(数据)
- 信令服务器:只传控制信息,不传媒体。用WebSocket实现最简单
下一节课,我们会深入RTCPeerConnection的内部机制,看看ICE协商到底是怎么工作的。到时候我会分享一个我踩过的坑——ICE重启导致连接中断的案例。