7、端到端连接建立:Offer/Answer流程、ICE候选者收集、连接状态机、重连机制

说实话,WebRTC 最核心的魅力,就是让两个浏览器能直接“对话”。但这个过程远没有想象中那么简单。你想想看,两个设备可能在不同的局域网后面,中间隔着 NAT、防火墙,甚至还有各种奇怪的代理。怎么找到对方?怎么建立连接?

这一章,我们就来拆解这个“握手”过程。我会结合我自己的踩坑经历,把 Offer/Answer、ICE、状态机、重连这些概念讲透。

7.1 Offer/Answer 流程:协商的起点

Offer/Answer,说白了就是“你提需求,我回应”。这是 WebRTC 连接建立的第一个步骤。没有这个协商,后面的一切都无从谈起。

流程其实很清晰:

  1. 发起方(Offerer) 创建一个 Offer,里面包含它支持的媒体能力(比如编解码器、分辨率、带宽等)。
  2. Offer 通过信令通道(比如 WebSocket)发送给 应答方(Answerer)
  3. 应答方收到 Offer 后,创建一个 Answer,表示“我接受这些能力,或者我调整一下”。
  4. Answer 再通过信令通道返回给发起方。

嗯,这里要注意:Offer 和 Answer 都是 SDP(Session Description Protocol)格式的文本。SDP 看起来像配置文件,里面一行一行地描述了媒体信息。

核心要点: Offer/Answer 只是“能力协商”,不是真正的媒体数据传输。它只是告诉对方“我能做什么,你看着办”。

我在项目中遇到过一个问题:有一次,Offer 里声明了 H.264 编码,但 Answer 方只支持 VP8。结果连接建立后,视频一直黑屏。后来我才意识到,SDP 协商失败时,WebRTC 不会自动降级,而是直接报错。所以,一定要在业务层做好编解码器的兼容性检查

7.2 ICE 候选者收集:找到对方的路

Offer/Answer 协商完能力后,接下来就是“找路”了。ICE(Interactive Connectivity Establishment)就是干这个的。

ICE 的核心思想是:收集所有可能的连接路径(候选者),然后尝试连接,直到成功。

候选者分为三种类型:

类型 说明 优先级
host 本机 IP 地址(比如 192.168.1.100) 最高
srflx 经过 NAT 映射后的公网 IP(通过 STUN 获取) 中等
relay 通过 TURN 服务器中转的地址 最低

为什么会有这么多类型?因为网络环境太复杂了。两个设备在同一个局域网时,直接用 host 候选者就能连上。但如果一个在 NAT 后面,另一个也在 NAT 后面,就需要 srflx 甚至 relay。

我个人习惯在调试时,先打印出所有候选者,看看有没有漏掉关键的地址。我曾经遇到过一个案例:客户反馈视频通话经常卡顿,排查后发现是 TURN 服务器带宽不够,导致 relay 候选者延迟很高。后来我们优化了 TURN 服务器的部署,问题才解决。

小技巧: 在浏览器中,可以通过 RTCPeerConnectiononicecandidate 事件来监听候选者的收集过程。每个候选者都会触发一次回调。

7.3 连接状态机:从“等待”到“连接”

WebRTC 的连接状态不是一成不变的。它有一个清晰的状态机,用来描述连接的当前阶段。

状态机的主要状态如下:

  • new:刚创建 PeerConnection,还没开始连接。
  • checking:正在检查候选者,尝试建立连接。
  • connected:至少有一条候选者路径成功建立了连接。
  • completed:所有候选者都检查完毕,连接稳定。
  • failed:所有候选者都失败了,连接无法建立。
  • disconnected:连接中断,但可能还能恢复。
  • closed:连接被主动关闭。

为什么会这样设计?因为网络是动态的。比如,你从 Wi-Fi 切换到 4G 时,IP 地址变了,原来的连接就会断开。WebRTC 的状态机就是为了应对这种变化。

我记得有一次,用户反馈视频通话突然中断,但几秒后又自动恢复了。查看日志发现,状态机从 connected 跳到了 disconnected,然后又回到了 connected。这是因为网络短暂波动,ICE 重新协商后找到了新的路径。

注意: 不要依赖 connected 状态来判断“连接是否可用”。因为 connected 只表示“曾经连上过”,不代表当前还能传输数据。建议结合 iceConnectionStateconnectionState 一起判断。

7.4 重连机制:网络波动也不怕

网络不可能永远稳定。Wi-Fi 信号弱、4G 切换、路由器重启……这些都会导致连接中断。WebRTC 内置了重连机制,但默认行为可能不够智能。

重连的核心逻辑是:

  1. 检测到连接断开(比如 iceConnectionState 变为 disconnected)。
  2. 触发 ICE 重新收集候选者(Restart ICE)。
  3. 重新执行 Offer/Answer 流程,协商新的连接参数。
  4. 尝试新的候选者路径,直到连接恢复。

但这里有个坑:默认的 ICE Restart 是自动触发的,但触发条件比较保守。有时候网络已经断了,但 WebRTC 还在傻等,导致用户感知到明显的卡顿。

我曾经在项目中做过一个优化:主动检测网络状态。比如,通过 WebSocket 的心跳包来判断网络是否正常。如果心跳超时,就主动调用 createOffer() 并设置 iceRestart: true,强制触发重连。这样,重连的响应速度比默认快了好几秒。

避坑指南: 我曾经在重连时忘记更新 SDP 中的 ICE 凭证,导致重连后一直认证失败。后来我养成了一个习惯:每次重连时,都重新生成 ICE 凭证,并确保信令通道能正确传递新的凭证。

7.5 知识体系总览

为了让你更直观地理解整个流程,我画了一张图。这张图展示了从 Offer/Answer 到 ICE 候选者收集,再到连接建立和重连的完整链路。

端到端连接建立流程 1. Offer/Answer 协商 2. ICE 候选者收集 3. 连接建立 创建 Offer 信令传输 创建 Answer 信令返回 host 候选者 srflx 候选者 relay 候选者 候选者排序 连通性检查 状态机更新 媒体传输 重连机制 关键点: Offer/Answer 协商能力 → ICE 收集路径 → 连通性检查 → 建立连接 网络波动时,触发 ICE Restart 重新协商 状态机流转:new → checking → connected → completed 失败时:checking → failed 或 connected → disconnected

这张图把整个流程分成了三个阶段。第一阶段是 Offer/Answer 协商,第二阶段是 ICE 候选者收集,第三阶段是连接建立和状态机管理。每个阶段都有子步骤,你可以对照着看。

好了,这一章的内容就到这里。端到端连接建立是 WebRTC 最核心的环节,也是最容易出问题的地方。理解了 Offer/Answer、ICE、状态机和重连机制,你就能应对大部分网络场景了。


公众号:蓝海资料掘金营,微信 deep3321