NAT穿透:NAT类型与WebRTC的穿透策略
说到NAT穿透,我得先跟你聊聊我早年踩过的一个坑。那时候我刚接触WebRTC,满心以为只要两端都连上网络,视频通话就能自动通。结果呢?本地测试好好的,一放到公网环境,画面就是出不来。折腾了两天,最后发现是NAT在搞鬼。
说白了,NAT就是你家路由器干的事——把内网IP映射成公网IP。但不同的路由器,映射方式不一样。这就导致了WebRTC能不能打通,完全取决于NAT的类型。
NAT的四种类型
我习惯把NAT分成四类,从最宽松到最严格。你想想看,这就像小区门禁系统,有的随便进,有的要刷卡,有的还要对暗号。
1. 完全锥形NAT(Full Cone NAT)
这是最友好的类型。内网主机A(192.168.1.100:5000)一旦向外发送过数据包,NAT就会在公网侧开一个端口(比如 203.0.113.5:8000)。任何外网主机只要往这个公网IP+端口发数据,都能穿透进来。
特点: 映射关系一旦建立,谁来访问都放行。
我在项目中遇到过:用STUN打洞时,完全锥形NAT几乎一次就能成功,成功率接近100%。
2. 限制锥形NAT(Restricted Cone NAT)
比完全锥形严格一点。它要求:外网主机必须先收到内网主机发过去的包,才能回传数据。换句话说,只有内网主机主动联系过的外网IP,才能穿透进来。
嗯,这里要注意:它只检查IP,不检查端口。所以只要IP对了,端口随便换都能通。
3. 端口限制锥形NAT(Port Restricted Cone NAT)
这个更严格了。不仅要求IP匹配,还要求端口也必须匹配。内网主机向 8.8.8.8:53 发了包,那只有 8.8.8.8:53 这个组合能回传数据。换个端口都不行。
我曾经调试过一个客户的环境,就是这种NAT。当时花了大半天才定位到问题——不是代码写错了,是NAT太严了。
4. 对称NAT(Symmetric NAT)
这是最难搞的类型。每次内网主机向不同的目标IP+端口发数据,NAT都会分配不同的公网端口。举个例子:
- A → B(1.2.3.4:80),NAT映射为 203.0.113.5:8000
- A → C(5.6.7.8:80),NAT映射为 203.0.113.5:8001
你看,同一个内网主机,同一个端口,只是目标不同,公网端口就变了。这就导致STUN服务器告诉你的映射地址,只对STUN服务器自己有效。其他主机想用这个地址打进来?门都没有。
避坑指南: 对称NAT是WebRTC穿透的头号敌人。我曾经在部署一个视频会议系统时,发现30%的用户都卡在对称NAT上。后来不得不引入TURN中继服务器才解决。
四种NAT对比
| NAT类型 | IP检查 | 端口检查 | 映射一致性 | 穿透难度 |
|---|---|---|---|---|
| 完全锥形 | 不检查 | 不检查 | 固定 | ★☆☆☆☆ |
| 限制锥形 | 检查 | 不检查 | 固定 | ★★☆☆☆ |
| 端口限制锥形 | 检查 | 检查 | 固定 | ★★★☆☆ |
| 对称NAT | 检查 | 检查 | 不固定 | ★★★★★ |
WebRTC如何穿透NAT
WebRTC的穿透策略,说白了就是一套组合拳。我把它总结为三步走:
第一步:收集候选地址(ICE Candidate)
WebRTC会收集三种类型的候选地址:
- Host候选: 本机内网IP,比如 192.168.1.100:5000
- Srflx候选: 通过STUN服务器获取的公网映射地址
- Relay候选: 通过TURN中继服务器分配的转发地址
我习惯把这一步叫做「摸清自己的底牌」。只有知道自己有哪些地址可用,才能决定下一步怎么打洞。
第二步:连通性检查(Connectivity Check)
双方交换候选地址后,开始互相发送STUN绑定请求。这个过程我简单说一下:
// 伪代码示意
Peer A 的候选列表: [192.168.1.100:5000, 203.0.113.5:8000, turn:relay.com:3478]
Peer B 的候选列表: [10.0.0.5:6000, 198.51.100.7:9000, turn:relay.com:3478]
// 检查顺序(优先级从高到低):
// 1. A的Host → B的Host(局域网直连)
// 2. A的Host → B的Srflx
// 3. A的Srflx → B的Srflx(NAT穿透)
// 4. 最后才用Relay(TURN中继)
为什么会按这个顺序?因为Host最快,Relay最慢还费带宽。我一般建议优先尝试P2P直连,实在不行再走中继。
第三步:NAT穿透的具体策略
针对不同的NAT类型,WebRTC会采用不同的策略:
对于完全锥形、限制锥形、端口限制锥形:
WebRTC通过STUN获取公网映射地址后,直接进行连通性检查。只要双方都发过包,NAT就会放行。成功率很高,我实测在80%以上。
对于对称NAT:
这是最头疼的情况。WebRTC的标准做法是:如果P2P打洞失败,就回退到TURN中继。但有个技巧——我曾经试过用「端口预测」法,就是猜测对称NAT下一个分配的端口号。虽然成功率不高(大概30%),但聊胜于无。
核心逻辑流程图
下面这张图,是我自己总结的WebRTC NAT穿透决策流程。你看一眼就能明白整个逻辑:
实际项目中的经验
我做了这么多年的WebRTC开发,总结了几条实战经验:
- STUN服务器一定要部署多个。 我曾经只部署了一个STUN服务器,结果那台机器挂了,所有用户都打不通。后来我至少部署3个,分布在不同的机房。
- TURN服务器是最后的保险。 虽然它费带宽(转发流量),但能保证100%连通。我一般建议预留TURN带宽,至少能承载20%的并发用户。
- ICE重启是个好技巧。 如果第一次打洞失败,可以触发ICE重启,重新收集候选地址。有时候换个端口就能通。
小提示: 在调试NAT穿透问题时,我习惯用 chrome://webrtc-internals 这个工具。它能实时显示ICE候选、连通性检查的状态,比看日志方便多了。
好了,关于NAT穿透的核心内容就这些。你想想看,其实WebRTC的穿透策略并不复杂——就是先试直连,不行就中继。但真正难的是理解NAT的行为,以及在不同场景下选择合适的策略。希望这些经验能帮你少走弯路。
公众号:蓝海资料掘金营,微信deep3321