5月28日 02:07

WebRTC的信令过程是怎样的?为什么需要信令服务器?

WebRTC的信令过程是怎样的?为什么需要信令服务器?

WebRTC 本身只负责音视频采集、编解码和点对点传输,但在两个浏览器建立直连之前,它们需要先交换一些关键信息——这个过程就叫信令(Signaling)。信令是 WebRTC 连接建立的前置环节,没有它,两个隔离在各自网络里的浏览器根本找不到对方。

信令过程的核心步骤

信令过程可以拆成两个并行的子流程:SDP 协商和 ICE 候选交换。它们不是串行的,而是几乎同时进行。

SDP 协商:双方就"用什么格式通话"达成一致

  1. 呼叫方创建 RTCPeerConnection,调用 createOffer() 生成 SDP Offer
  2. 呼叫方调用 setLocalDescription() 保存本地描述,然后通过信令服务器将 Offer 转发给应答方
  3. 应答方收到 Offer 后调用 setRemoteDescription() 设置远端描述
  4. 应答方调用 createAnswer() 生成 SDP Answer,再通过信令服务器回传
  5. 呼叫方收到 Answer 后调用 setRemoteDescription() 完成协商

SDP 里包含了什么?媒体格式(编解码器、payload type)、带宽限制、ICE 账号密码、DTLS 指纹等。双方通过 Offer/Answer 交换这些信息,选出共同支持的编码方案。

ICE 候选交换:双方就"通过哪条网络路径连接"达成一致

  1. 双方创建 RTCPeerConnection 后,ICE Agent 开始收集候选地址
  2. 每发现一个候选,触发 onicecandidate 事件,通过信令服务器发送给对方
  3. 对方收到后调用 addIceCandidate() 添加候选

ICE 候选有三种类型:

  • Host 候选:本机网卡地址,优先级最高
  • Server Reflexive 候选(srflx):通过 STUN 服务器获取的公网映射地址
  • Relay 候选(relay):TURN 服务器分配的中继地址,优先级最低但穿透能力最强

实际项目中常用 Trickle ICE 策略:不等所有候选收集完毕,而是找到一个就发一个,加快连接速度。

连接建立

SDP 协商和 ICE 候选交换完成后,ICE 会对候选对进行连通性检查。一旦找到可用的路径,DTLS 握手随即完成,SRTP 通道建立,双方开始传输音视频数据。

为什么需要信令服务器?

WebRTC 规范故意不定义信令协议,但信令服务器在连接建立中不可或缺,原因如下:

NAT 穿透的必要条件

大多数设备在 NAT 或防火墙后面,无法直接被外部访问。信令服务器是双方交换 ICE 候选的唯一通道——没有它,两个浏览器根本不知道对方的公网地址和端口,也无法协调 STUN/TURN 的使用。

媒体协商的桥梁

两个浏览器支持的编解码器可能不同(比如 Chrome 支持 VP8/VP9/AV1,Safari 可能只支持 H.264)。SDP 协商让双方在连接建立前就确定好共同支持的编码方案,避免连接成功却发现无法解码的尴尬。

会话状态管理

实际应用中还需要处理房间创建、用户加入/离开、通话挂断等业务逻辑。这些都不在 WebRTC 规范内,需要信令服务器配合业务层实现。

安全认证的起点

DTLS 证书指纹通过 SDP 传递,确保连接建立后双方可以验证对方身份。如果指纹不匹配,连接会被拒绝。信令服务器是这个信任链的传输通道。

信令协议怎么选?

WebRTC 不限制信令协议,常见的选型:

  • WebSocket:最主流的方案,全双工、低延迟,适合实时通信场景
  • Socket.io:在 WebSocket 基础上加了房间、广播等语义,开发效率高
  • HTTP 轮询:实时性差,仅作为降级方案

生产环境建议使用 WSS(加密的 WebSocket),防止信令数据被截获或篡改。

常见踩坑

  • 忘记在 setRemoteDescription 之前设置好 ontrack 等事件监听,导致远端流丢失
  • ICE 候选在 SDP 协商完成前到达,调用 addIceCandidate() 会报错,需要做缓冲处理
  • 信令服务器只存在单进程内存中,服务器重启所有房间丢失,建议用 Redis 共享会话状态
标签:WebRTC