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)是最轻量的穿透方案。它的工作方式很简单:

  1. 客户端向 STUN 服务器发送请求
  2. 服务器看到请求的来源 IP 和端口
  3. 服务器把这些信息返回给客户端
  4. 客户端就知道了自己的公网地址

嗯,这里要注意: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 的工作流程是这样的:

  1. 收集候选者(Candidate):包括本地地址、STUN 反射地址、TURN 中继地址
  2. 排序候选者:按优先级排列,本地地址 > STUN 地址 > TURN 地址
  3. 连通性检查:按优先级依次尝试连接,直到成功
  4. 选定路径:使用第一个成功的候选者对

你想想看,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 连通性检查,再到最终的数据传输。

WebRTC 网络穿透核心流程 1. 收集候选者 本地 / STUN / TURN 2. 排序候选者 按优先级排列 3. 连通性检查 STUN 绑定请求 P2P 成功? P2P 直连 TURN 中继 ICE 框架自动选择最优路径:P2P 优先,TURN 兜底

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。这样既保证了连接成功率,又控制了成本。


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