13、NAT穿透与STUN/TURN:NAT类型、STUN服务器的作用、TURN服务器的中继原理、部署TURN(Coturn)
各位好,欢迎来到第十三章。今天聊的话题,是WebRTC实战中绕不开的一个坎——NAT穿透。
说实话,我最早接触WebRTC时,以为只要两端都连上网络,就能直接P2P通信。结果第一次联调就翻车了。两边都在公司内网,视频死活连不上。后来才明白,是NAT在中间搞鬼。
这一章,我们就来彻底搞懂NAT穿透的原理,以及STUN和TURN这两个关键角色。我会结合我自己的踩坑经历,帮你把这块硬骨头啃下来。
13.1 为什么需要NAT穿透?
先问一个问题:你的电脑在局域网里,IP是192.168.1.10。你想和另一个局域网里的朋友视频通话。你们俩的IP都是私有的,互联网上根本找不到你们。怎么办?
答案就是NAT(网络地址转换)。路由器把你的私有IP映射成一个公网IP+端口,这样数据才能出去。但问题来了——这个映射是临时的,而且每个路由器行为不一样。这就导致了NAT穿透的复杂性。
我在项目中遇到过最典型的情况:两个用户都在公司内网,都经过多层NAT。用STUN打洞,死活打不通。最后只能上TURN中继。嗯,这就是现实。
13.2 NAT的四种类型
要理解穿透,先得知道NAT分几种。我习惯把它们分成四类,按严格程度排序:
| NAT类型 | 行为特点 | 穿透难度 |
|---|---|---|
| 完全锥形NAT | 只要映射了一个公网端口,任何外网主机都能通过这个端口访问内网 | 容易 |
| 限制锥形NAT | 只有内网主机曾经发过数据的目标IP,才能从那个IP回访 | 中等 |
| 端口限制锥形NAT | 不仅限制IP,还限制端口。必须内网发过数据的目标IP+端口才能回访 | 较难 |
| 对称NAT | 每次发往不同目标IP:端口,都会分配不同的公网端口。映射不固定 | 极难(STUN基本无效) |
说白了,前三种NAT,STUN还有机会打洞成功。但对称NAT,基本只能靠TURN中继了。
核心结论:对称NAT下,P2P打洞成功率极低。如果你发现用户连不上,先检查NAT类型。
13.3 STUN服务器的作用
STUN(Session Traversal Utilities for NAT)干的事情很简单:帮你找到自己的公网IP和端口。
流程是这样的:
- 你的客户端向STUN服务器发一个请求
- STUN服务器看到请求来自哪个公网IP:端口
- 服务器把这个地址返回给你
- 你拿到后,把这个地址通过信令发给对方
- 对方尝试连接这个地址
听起来很完美对吧?但有个坑——STUN只能帮你拿到映射地址,能不能连上,取决于NAT类型。我曾经遇到一个案例,STUN返回的地址完全正确,但对方就是连不上。查了半天,发现是端口限制锥形NAT,对方IP不在白名单里。
我的建议:不要完全依赖STUN。把它当作第一选择,但一定要有备用方案(TURN)。
13.4 TURN服务器的中继原理
当STUN打洞失败时,TURN就上场了。TURN(Traversal Using Relays around NAT)的原理很简单:所有数据都经过服务器中转。
说白了,就是放弃P2P,走服务器转发。代价是带宽和延迟,但保证能连通。
TURN的工作流程:
- 客户端A向TURN服务器申请一个中继地址
- TURN分配一个公网IP:端口,称为中继地址
- A把这个中继地址通过信令发给B
- B向这个中继地址发数据
- TURN把数据转发给A
反过来也一样。这样,即使双方都在对称NAT后面,也能通信。
注意:TURN会消耗大量带宽。一个视频通话,如果走TURN中继,服务器带宽消耗是双向的。我曾经部署的TURN服务器,高峰期带宽跑满,差点把公司网络搞瘫。
13.5 部署TURN(Coturn)
目前最流行的TURN服务器是Coturn。我部署过好几次,踩了不少坑。下面分享一个稳定可靠的部署方案。
13.5.1 安装Coturn
以Ubuntu为例:
sudo apt update
sudo apt install coturn
安装完成后,配置文件在 /etc/turnserver.conf。
13.5.2 基本配置
我个人习惯的配置如下:
# 监听端口
listening-port=3478
# TLS端口(可选)
tls-listening-port=5349
# 中继端口范围
min-port=49152
max-port=65535
# 认证方式(推荐使用长期凭证)
fingerprint
lt-cred-mech
# 用户配置(用户名:密码)
user=myuser:mypassword
# 域名或公网IP
realm=example.com
# 日志
log-file=/var/log/turnserver.log
verbose
避坑指南:我曾经忘记配置min-port和max-port,结果Coturn随机使用端口,导致防火墙规则失效。建议明确指定端口范围,并在防火墙中放行。
13.5.3 启动与验证
sudo systemctl start coturn
sudo systemctl enable coturn
验证是否运行:
sudo netstat -tulpn | grep 3478
如果看到coturn在监听,说明启动成功。
13.5.4 客户端集成
在WebRTC中配置TURN服务器:
const iceServers = [
{
urls: 'stun:stun.example.com:3478'
},
{
urls: 'turn:turn.example.com:3478',
username: 'myuser',
credential: 'mypassword'
}
];
const pc = new RTCPeerConnection({ iceServers });
这里要注意,生产环境中不要把密码硬编码在客户端。我一般用临时凭证,服务端动态生成用户名和密码,有效期只有几分钟。
13.6 知识体系总览
下面这张图,是我自己总结的NAT穿透知识体系。你可以把它当作一个快速参考:
13.7 总结
这一章我们聊了NAT穿透的核心内容。说白了,STUN是帮你找路,TURN是帮你修路。实际项目中,我建议两者都配,让WebRTC自己选择最优路径。
部署TURN时,记得注意带宽和防火墙。我曾经因为忘记开端口,排查了一整天。嗯,这些坑你们就别再踩了。
好了,这一章就到这里。希望你能把NAT穿透这块彻底搞懂。有问题欢迎交流。
公众号:蓝海资料掘金营,微信deep3321