14、STUN/TURN服务器:STUN的作用、TURN的作用、搭建Coturn服务器、配置STUN/TURN地址
WebRTC 的 P2P 连接,说白了就是两个浏览器之间直接传数据。但现实世界没这么理想——你家电脑在路由器后面,对方也在路由器后面,两边都不知道对方的真实地址。这时候就需要 STUN 和 TURN 来帮忙了。
我最早接触这块时,觉得 STUN 和 TURN 不就是个地址翻译嘛,有啥难的?结果真到项目里,踩了不少坑。今天咱们就把这两个东西彻底讲清楚。
STUN 的作用:帮你找到自己的门牌号
STUN 的全称是 Session Traversal Utilities for NAT,翻译过来就是「NAT 会话穿越工具」。它的核心任务只有一个:告诉你的浏览器,你的公网 IP 和端口是什么。
你想想看,你的电脑在局域网里,IP 是 192.168.1.x 这种私有地址。当你要跟另一个浏览器通信时,你得告诉对方「我在哪」。但对方要的是公网地址,不是你的内网地址。STUN 服务器就是干这个的——你发个请求过去,它看看你的源 IP 和端口,然后原封不动地返回给你。
STUN 的核心能力:
- 获取公网 IP 和端口映射
- 检测 NAT 类型(锥形、对称型等)
- 判断是否可以直接 P2P 连接
我在项目中遇到过一种情况:用户在公司内网,网络环境极其复杂。STUN 返回了公网地址,但对方就是连不上。后来发现是公司的防火墙做了端口限制。嗯,这里要注意——STUN 只负责告诉你地址,不保证能连通。
TURN 的作用:最后的保底方案
当 STUN 搞不定时,TURN 就上场了。TURN 的全称是 Traversal Using Relays around NAT,说白了就是「中继转发」。它不尝试穿透 NAT,而是直接让所有数据都经过服务器中转。
你可能会问:那为什么不直接用 TURN?因为成本高啊。TURN 服务器要承担所有媒体流的带宽,视频通话一小时可能跑掉几个 G 的流量。所以我们的策略是:优先用 STUN 尝试 P2P,实在不行才 fallback 到 TURN。
什么时候必须用 TURN?
- 对称型 NAT(最常见的企业网络)
- 防火墙阻止 UDP 通信
- 两端都在严格的 NAT 后面
- 移动网络(4G/5G)下的某些场景
我曾经在一个视频会议项目里,发现 30% 的用户都 fallback 到了 TURN。一开始以为是 STUN 配置有问题,排查了半天才发现是用户的运营商做了端口限制。从那以后,我建议每个项目都预留足够的 TURN 带宽。
STUN 和 TURN 的工作流程
下面这张图展示了 WebRTC 建立连接时的完整流程:
流程其实不复杂:先通过 STUN 拿到自己的公网地址,然后通过信令服务器交换给对端。如果 P2P 连不上,就退而求其次走 TURN 中继。
搭建 Coturn 服务器
Coturn 是目前最流行的开源 STUN/TURN 服务器。我个人的习惯是用 Docker 部署,省心又干净。下面给出两种方式:
方式一:Docker 部署(推荐)
# 拉取镜像
docker pull coturn/coturn
# 运行容器(简单模式)
docker run -d --network=host \
--name=coturn \
coturn/coturn \
-n --log-file=stdout \
--listening-port=3478 \
--min-port=49152 --max-port=65535 \
--realm=example.com \
--user=webrtc:password123
参数说明:
--network=host:使用宿主机网络,避免端口映射问题--listening-port:STUN/TURN 监听端口,默认 3478--min-port / --max-port:TURN 中继使用的端口范围--user:用户名:密码,多个用户用逗号分隔
方式二:源码编译安装
# 安装依赖
sudo apt-get install libssl-dev libevent-dev libsqlite3-dev
# 下载源码
wget https://github.com/coturn/coturn/archive/refs/tags/4.6.2.tar.gz
tar -xzf 4.6.2.tar.gz
cd coturn-4.6.2
# 编译安装
./configure
make
sudo make install
# 启动服务
turnserver -c /usr/local/etc/turnserver.conf
我曾经在生产环境用过源码编译,后来发现升级维护太麻烦。现在一律用 Docker,配置改起来也方便。
配置 STUN/TURN 地址
服务器搭好了,怎么在 WebRTC 里用?关键在 RTCPeerConnection 的配置里:
const pcConfig = {
iceServers: [
{
urls: 'stun:stun.example.com:3478'
},
{
urls: 'turn:turn.example.com:3478',
username: 'webrtc',
credential: 'password123'
}
]
};
const pc = new RTCPeerConnection(pcConfig);
重要提醒:
- STUN 不需要认证,TURN 必须要有用户名和密码
- 生产环境不要硬编码密码,建议通过信令服务器动态下发
- 可以配置多个 STUN/TURN 地址,WebRTC 会自动选择最优的
- TURN 的端口范围要开放,否则中继会失败
这里有个坑:很多人只配了 STUN,没配 TURN。结果在复杂网络下连接失败,还以为是代码问题。我建议永远同时配置 STUN 和 TURN,哪怕 TURN 只用做 fallback。
验证配置是否生效
配置完了怎么知道好不好使?打开浏览器的开发者工具,看 chrome://webrtc-internals:
| 字段 | 说明 | 正常值 |
|---|---|---|
| candidateType | 候选者类型 | host / srflx / relay |
| relayProtocol | 中继协议 | udp / tcp / tls |
| localCandidate | 本地候选者 | 内网 IP 或公网 IP |
| remoteCandidate | 远端候选者 | 对端的 IP 和端口 |
如果看到 relay 类型的 candidate,说明 TURN 生效了。如果只有 host 和 srflx,说明走的是 P2P 或 STUN。
一句话总结:
STUN 帮你找到路,TURN 帮你铺条路。能走 STUN 就走 STUN,走不通再走 TURN。搭建 Coturn 用 Docker 最省事,配置时记得 STUN 和 TURN 一起配。
嗯,STUN/TURN 这块就讲这么多。实际项目中,你可能会遇到各种网络环境,但核心逻辑不变——理解 NAT 穿透的原理,比死记硬背配置参数重要得多。
公众号:蓝海资料掘金营,微信 deep3321