25、STUN/TURN:NAT穿透原理、STUN服务器配置、TURN中继服务器配置
说到WebRTC,绕不开的一个话题就是NAT穿透。我刚开始做音视频的时候,以为只要两端都连上公网就能直接P2P通信。结果第一次联调就翻车了——两边都在公司内网,互相看不见。嗯,那时候我才真正意识到,NAT这堵墙有多烦人。
说白了,WebRTC的底层逻辑是尽量走P2P,因为延迟低、带宽省。但现实是,大部分设备都躲在NAT后面。这时候就需要STUN和TURN这两位“救兵”了。今天我们就来聊聊它们是怎么工作的,以及怎么配置。
NAT穿透:为什么需要STUN和TURN?
先看一个最简单的场景。你在家里用笔记本,连的是路由器。路由器分配给你一个内网IP,比如192.168.1.5。你想和另一个同样在内网的朋友建立视频通话。你们俩的电脑都不知道对方的公网IP和端口。这就是NAT带来的问题。
STUN(Session Traversal Utilities for NAT)的作用很简单:帮你找到自己的公网IP和端口。你向STUN服务器发个请求,服务器看到你的请求是从哪个公网IP和端口来的,然后把这个信息返回给你。这样你就知道了自己的“外网身份”。
但STUN不是万能的。我在项目中遇到过一种情况:对称型NAT。这种NAT下,每次你向不同目标发请求,它都会分配不同的端口。STUN拿到的映射关系只对STUN服务器有效,换一个目标就不行了。这时候STUN就失效了。
那怎么办?TURN(Traversal Using Relays around NAT)上场。TURN服务器充当一个中继。你的媒体数据先发给TURN服务器,再由它转发给对方。虽然延迟高了,但至少能通。说白了,TURN是最后的保底方案。
STUN服务器配置实战
配置STUN服务器其实不复杂。WebRTC里,你只需要在创建RTCPeerConnection时传入一个iceServers数组。我个人习惯把STUN和TURN都配好,这样ICE框架会自动选择最优路径。
下面是一个典型的STUN配置示例:
const pc = new RTCPeerConnection({
iceServers: [
{
urls: 'stun:stun.l.google.com:19302'
}
]
});
这里用的是Google的公共STUN服务器。你可能会问:生产环境能用这个吗?我的建议是,开发测试可以,但正式项目最好自建STUN服务器,或者用云服务商的。因为公共STUN服务器不稳定,而且有频率限制。
自建STUN服务器也很简单。我常用coturn这个开源项目。安装后,配置一下监听端口和网卡就行。下面是一个最小配置:
# coturn 配置文件示例
listening-port=3478
fingerprint
lt-cred-mech
user=myuser:mypassword
realm=myrealm
启动后,把urls改成你自己的服务器地址:
iceServers: [
{
urls: 'stun:your-server-ip:3478'
}
]
TURN中继服务器配置
TURN的配置比STUN稍微复杂一点,因为需要认证。毕竟TURN会消耗服务器带宽,不能随便让人用。coturn同样支持TURN,配置时加上中继相关的参数即可。
下面是一个完整的coturn配置,同时支持STUN和TURN:
listening-port=3478
tls-listening-port=5349
fingerprint
lt-cred-mech
user=myuser:mypassword
realm=myrealm
total-quota=100
stale-nonce
no-loopback-peers
no-multicast-peers
mobility
relay-device=eth0
relay-ip=your-public-ip
min-port=49152
max-port=65535
注意这里的relay-ip要填服务器的公网IP。端口范围建议开大一点,因为每个连接会占用一个端口。我在生产环境遇到过端口耗尽的问题,后来把范围扩到10000个端口才解决。
前端配置时,需要加上用户名和密码:
iceServers: [
{
urls: 'turn:your-server-ip:3478',
username: 'myuser',
credential: 'mypassword'
}
]
ICE流程与NAT穿透决策
ICE(Interactive Connectivity Establishment)是WebRTC的“交通指挥官”。它收集所有可能的候选者(host、srflx、relay),然后按优先级排序,逐个尝试连接。一旦找到可用的路径,就停止尝试。
下面这张图展示了ICE的决策流程:
ICE会先尝试host候选者(局域网直连)。如果失败,再尝试srflx候选者(STUN穿透)。最后才尝试relay候选者(TURN中继)。这个顺序是固定的,因为P2P延迟最低,中继延迟最高。
我曾经遇到过一个坑:明明STUN拿到了公网地址,但就是连不上。后来发现是防火墙把UDP端口封了。ICE会检测到UDP不通,自动回退到TCP,甚至TLS。所以配置TURN时,最好同时支持UDP和TCP。
避坑指南
- STUN服务器不要只配一个。 我建议至少配两个,一个挂了还有备用。Google的公共STUN服务器虽然好用,但偶尔会超时。
- TURN服务器的带宽要算好。 每个视频通话大约需要1-2Mbps的上行带宽。如果有100个用户同时走中继,服务器带宽至少要200Mbps。
- 认证凭证要定期更换。 我见过有人把TURN密码写死在客户端,结果被刷了几百G流量。用短期token,比如有效期1小时。
- 测试时打开chrome://webrtc-internals。 这里面能看到ICE候选者、连接状态、丢包率。排查问题必备。
好了,关于STUN和TURN的配置就聊到这里。实际项目中,你可能还需要考虑服务器部署位置、负载均衡、带宽监控等问题。但核心原理和配置方法,就是上面这些。动手搭一个试试,你会发现NAT穿透其实没那么神秘。