6、网络穿透:STUN/TURN协议、ICE框架、NAT类型检测
WebRTC 最核心的难题是什么?不是编解码,不是传输优化,而是——怎么让两个设备在复杂的网络环境下找到对方。
说白了,就是网络穿透。我刚开始做 WebRTC 时,以为只要把 SDP 交换了,媒体流就能通。结果呢?在办公室内网测得好好的,一放到公网环境,视频就是黑的。后来我才意识到,NAT 和防火墙才是真正的拦路虎。
这一章,我们就来拆解 WebRTC 的网络穿透机制:STUN、TURN、ICE,以及 NAT 类型检测。你想想看,没有这些,你的 App 就只能在内网自嗨。
6.1 为什么需要网络穿透?
先看一个场景:你的手机连着家里的 WiFi,对方的手机在公司的 4G 网络下。两台设备都在各自的局域网里,IP 地址是私有的(比如 192.168.x.x)。
公网上,这些私有 IP 是不可路由的。所以,直接拿本地 IP 去连接对方,肯定失败。
那怎么办?我们需要一个“中间人”来帮忙:
- 告诉对方,你的公网地址是什么
- 如果公网地址也不行,就帮你中转数据
这就是 STUN 和 TURN 的由来。
核心概念:NAT(网络地址转换)让多个设备共享一个公网 IP,但也阻断了外部主动发起的连接。WebRTC 必须绕过这个限制。
6.2 STUN 协议:帮我看看我的公网地址
STUN(Session Traversal Utilities for NAT)是最轻量的穿透方案。它的工作方式很简单:
- 客户端向 STUN 服务器发送请求
- 服务器看到请求的来源 IP 和端口
- 服务器把这些信息返回给客户端
- 客户端就知道了自己的公网地址
嗯,这里要注意:STUN 只负责“发现”,不负责“中转”。它帮你拿到公网地址后,剩下的连接尝试由 ICE 框架来完成。
我的经验:STUN 服务器通常用 3478 端口。我个人习惯在项目中部署至少两台 STUN 服务器,防止单点故障。曾经有一次,STUN 服务器挂了,所有用户的连接都卡在“收集候选者”阶段,排查了半天才发现是 DNS 解析的问题。
6.3 TURN 协议:最后的保底方案
STUN 不是万能的。有些 NAT 类型(比如对称型 NAT)或者企业防火墙,会直接阻止 P2P 连接。这时候,TURN(Traversal Using Relays around NAT)就派上用场了。
TURN 的原理是:所有数据都经过服务器中转。客户端 A 把数据发给 TURN 服务器,服务器再转发给客户端 B。反过来也一样。
代价是什么?带宽和延迟。TURN 服务器要承担所有媒体流的转发,成本很高。所以,TURN 是最后的保底方案,能不用就不用。
| 特性 | STUN | TURN |
|---|---|---|
| 功能 | 发现公网地址 | 中转媒体数据 |
| 带宽消耗 | 极低(仅信令) | 高(全部流量) |
| 延迟 | 低 | 较高 |
| 适用场景 | 大部分 NAT 环境 | 对称 NAT / 防火墙 |
避坑指南:我曾经在项目中只部署了 STUN 服务器,结果有 30% 的用户连不上。后来加了 TURN 服务器,连接成功率才提升到 99% 以上。记住:STUN 是首选,TURN 是兜底。
6.4 ICE 框架:智能选择最佳路径
ICE(Interactive Connectivity Establishment)不是单独的协议,而是一个框架。它把 STUN、TURN 和本地地址整合起来,让 WebRTC 自动选择最优的连接路径。
ICE 的工作流程是这样的:
- 收集候选者(Candidate):包括本地地址、STUN 反射地址、TURN 中继地址
- 排序候选者:按优先级排列,本地地址 > STUN 地址 > TURN 地址
- 连通性检查:按优先级依次尝试连接,直到成功
- 选定路径:使用第一个成功的候选者对
你想想看,ICE 就像一个智能路由,它会自动帮你选最快的路。如果 P2P 能通,就不走服务器;如果 P2P 不通,就退而求其次走 TURN。
关键点:ICE 的连通性检查是通过 STUN 绑定请求完成的。每个候选者对都要发送 STUN 消息来验证是否可达。
6.5 NAT 类型检测
不同的 NAT 类型,穿透难度不一样。ICE 框架在收集候选者时,会隐式地检测 NAT 类型。常见的 NAT 类型有:
- 完全锥型 NAT:最宽松,任何外部主机都能通过映射地址访问
- 限制锥型 NAT:只有内部主机曾经访问过的外部主机才能回连
- 端口限制锥型 NAT:比限制锥型更严格,还限制了端口
- 对称型 NAT:最严格,每次请求都映射不同的端口,P2P 几乎不可能
检测方法其实不复杂:客户端向 STUN 服务器发送请求,服务器返回不同的响应,客户端根据响应判断 NAT 行为。
我的建议:在移动端开发时,可以先用一个简单的 NAT 检测工具(比如 stunclient)测试一下当前网络环境。如果发现是对称型 NAT,直接走 TURN 就好,别浪费时间去尝试 P2P。
6.6 核心逻辑流程图
下面这张图展示了 WebRTC 网络穿透的完整流程。从收集候选者到 ICE 连通性检查,再到最终的数据传输。
6.7 移动端实战要点
在移动端开发 WebRTC 时,有几个地方需要特别注意:
- 网络切换:手机从 WiFi 切到 4G 时,ICE 会重新收集候选者。你需要监听
oniceconnectionstatechange事件,及时处理重连 - 省电模式:ICE 的连通性检查会频繁发送 STUN 消息。我建议在后台时降低检查频率,或者暂停 ICE
- TURN 服务器成本:TURN 流量很贵。你可以根据用户网络类型动态决定是否启用 TURN。比如,检测到对称型 NAT 才走 TURN
曾经踩过的坑:在 Android 上,如果 App 进入后台,系统可能会杀掉 WebRTC 的线程。ICE 状态会变成 ICE_CONNECTION_CHECKING 然后超时。解决方案是:在 onPause() 时保存 ICE 状态,onResume() 时恢复。
6.8 小结
网络穿透是 WebRTC 的基石。没有它,P2P 就是空谈。STUN 帮你发现公网地址,TURN 帮你中转数据,ICE 帮你智能选择路径。NAT 类型检测则决定了你该走哪条路。
在实际项目中,我建议你:
- 至少部署两台 STUN 服务器
- 按需使用 TURN,不要全量开启
- 监听 ICE 状态变化,做好重连逻辑
记住一句话:能 P2P 就 P2P,不行再走 TURN。这样既保证了连接成功率,又控制了成本。