9、STUN/TURN 调试:使用 stunclient 工具测试 STUN 服务器,分析 TURN 分配失败原因

做 WebRTC 开发,最头疼的问题之一就是连不上。我见过太多团队,花了两周时间排查信令、排查媒体流,最后发现——是 STUN/TURN 服务器没配好。说白了,你 ICE 候选者都收集不全,还谈什么 P2P 连接?

这一节,咱们就聚焦在 STUN/TURN 的调试上。我会带你用 stunclient 这个命令行工具,亲手测试 STUN 服务器是否正常,然后深入分析 TURN 分配失败的各种原因。嗯,这些坑我基本都踩过,希望能帮你省点时间。

9.1 为什么需要 STUN/TURN 调试?

先简单回顾一下。STUN 帮你在 NAT 后面拿到公网地址,TURN 则是在 P2P 打不通时做中继。但问题是——你怎么知道你的 STUN/TURN 服务器配置对了?

我曾经接手过一个项目,线上用户反馈频繁掉线。查了半天,发现 STUN 服务器返回的地址根本不对,导致 ICE 协商一直失败。你想想看,如果连最基本的 STUN 请求都得不到正确响应,后面的所有工作都是白费。

所以,调试 STUN/TURN 是 WebRTC 实战中的基本功。别等到线上出问题了再临时抱佛脚。

9.2 使用 stunclient 测试 STUN 服务器

stunclient 是一个轻量级的命令行工具,属于 stun 项目的一部分。它能直接发送 STUN 绑定请求,并解析返回的消息。我个人习惯用它来做快速验证,比写代码调试快得多。

9.2.1 安装 stunclient

在 Ubuntu/Debian 上安装很简单:

sudo apt-get install stun

在 macOS 上可以用 Homebrew:

brew install stun

安装完成后,直接运行 stunclient --help 就能看到参数说明。

9.2.2 基本用法

测试一个 STUN 服务器,只需要指定服务器地址和端口:

stunclient stun.l.google.com 19302

输出大概是这样:

STUN client test
Binding test: success
Local address: 192.168.1.100:54321
Mapped address: 123.45.67.89:54321

看到 Binding test: success 就说明 STUN 服务器正常工作。Mapped address 就是你的公网 IP 和端口。如果这个地址和你预期的公网地址一致,那基本就没问题。

小提示: 如果 Mapped address 显示的是内网地址(比如 192.168.x.x),说明 STUN 服务器可能没有正确穿透你的 NAT。这时候需要检查你的网络环境,或者换一个 STUN 服务器试试。

9.2.3 测试不同的 NAT 类型

有时候,STUN 服务器能响应,但返回的地址并不一定可用。这取决于你的 NAT 类型。你可以用 stunclient--mode full 参数做更详细的测试:

stunclient --mode full stun.l.google.com 19302

输出会包含更多信息,比如 NAT 类型、是否支持 hairpin 等。我个人建议,在部署前至少用三种不同的网络环境(公司内网、家庭宽带、4G 热点)测试一遍,确保兼容性。

9.3 分析 TURN 分配失败原因

TURN 分配失败比 STUN 失败更常见,也更难排查。为什么?因为 TURN 涉及认证、带宽分配、端口资源等多个环节。任何一个环节出问题,都会导致分配失败。

我曾经遇到过一个案例:TURN 服务器配置完全正确,但用户就是连不上。最后发现是 TURN 服务器的端口范围被防火墙限制了。嗯,这种问题最坑人。

9.3.1 常见错误码及含义

TURN 分配失败时,服务器会返回一个错误码。下面是我整理的一些常见错误码:

错误码 含义 常见原因
401 Unauthorized 认证失败,用户名或密码错误
403 Forbidden 用户被禁止使用 TURN 服务
437 Allocation Mismatch 请求的 Allocation 与现有冲突
438 Stale Nonce Nonce 过期,需要重新认证
441 Wrong Credentials 凭据错误
486 Allocation Quota Reached 服务器资源耗尽,无法分配

看到 401 或 438,基本就是认证问题。看到 486,说明服务器负载太高了,需要扩容。

9.3.2 使用 stunclient 测试 TURN 分配

stunclient 也支持 TURN 协议。你可以用 --protocol turn 参数来测试:

stunclient --protocol turn --username your_username --password your_password turn.example.com 3478

如果分配成功,你会看到类似这样的输出:

TURN client test
Allocation: success
Relayed address: 203.0.113.50:49152

如果分配失败,会显示错误码和错误信息。比如:

TURN client test
Allocation: failed
Error code: 401
Error message: Unauthorized

这时候,你就要去检查用户名和密码了。我遇到过好几次,都是因为密码中包含了特殊字符,导致在配置文件中被转义了。

9.3.3 排查 TURN 分配失败的步骤

当 TURN 分配失败时,我一般按以下步骤排查:

  1. 检查网络连通性:先用 pingtelnet 确认 TURN 服务器的 IP 和端口是否可达。
  2. 验证认证信息:用 stunclient 手动测试,确认用户名和密码正确。
  3. 检查防火墙规则:TURN 需要开放多个端口(通常是 3478 和 5349),以及 UDP/TCP 端口范围。
  4. 查看服务器日志:如果 TURN 服务器是自己部署的,去日志里找错误信息。
  5. 检查资源配额:确认服务器没有达到分配上限。
注意: TURN 分配失败时,不要只盯着客户端。很多时候问题出在服务器端。我曾经排查了整整一天,最后发现是 TURN 服务器的磁盘空间满了,导致无法写入新的 Allocation 记录。

9.4 实战:用 stunclient 诊断一个真实问题

假设你遇到了这样一个场景:用户反馈在某些网络环境下无法建立连接。你怀疑是 TURN 服务器的问题。怎么用 stunclient 来诊断?

第一步,先测试 STUN:

stunclient stun.l.google.com 19302

如果 STUN 成功,说明基本网络没问题。第二步,测试 TURN:

stunclient --protocol turn --username testuser --password testpass turn.mycompany.com 3478

如果 TURN 分配失败,比如返回 403,那就说明用户被禁止了。这时候需要检查 TURN 服务器的用户权限配置。

如果返回 486,说明服务器资源不足。你可以用 stunclient--lifetime 参数请求一个更短的分配时间,看看是否能成功:

stunclient --protocol turn --username testuser --password testpass --lifetime 60 turn.mycompany.com 3478

如果短生命周期的分配成功,那基本可以确认是资源配额问题。你需要联系运维人员扩容。

9.5 知识体系:STUN/TURN 调试核心逻辑

下面这张图,是我自己总结的 STUN/TURN 调试流程。你可以把它当作一个检查清单:

STUN/TURN 调试核心逻辑 开始调试 步骤1:使用 stunclient 测试 STUN 服务器 STUN 成功? 检查网络/NAT/防火墙 更换 STUN 服务器 步骤2:使用 stunclient 测试 TURN 分配 TURN 成功? 完成 检查错误码 排查认证/资源/防火墙 核心工具:stunclient | 关键指标:错误码、Mapped Address、Relayed Address

这张图的核心逻辑很简单:先测 STUN,再测 TURN。STUN 失败就排查网络和 NAT,TURN 失败就根据错误码定位具体原因。按这个流程走,大部分问题都能快速定位。

9.6 避坑指南

最后,分享几个我踩过的坑:

  • 不要忽略 UDP 和 TCP 的区别:有些 TURN 服务器只支持 UDP,有些同时支持 TCP。如果你的客户端强制使用 TCP,而服务器只支持 UDP,分配就会失败。用 stunclient--protocol 参数分别测试一下。
  • 注意 TURN 的认证机制:TURN 使用长期凭证机制(long-term credential),需要先获取一个 Nonce,然后再用 Nonce 计算 HMAC。如果客户端和服务器的时间不同步,Nonce 可能会被判定为过期。我遇到过因为服务器时区设置错误导致的认证失败。
  • 端口范围限制:很多企业防火墙只开放了 3478 端口,但 TURN 分配成功后,媒体流会使用其他端口(比如 49152-65535)。如果这些端口被封锁,即使分配成功,媒体流也无法传输。用 stunclient 测试时,可以加上 --verbosity 3 查看详细的端口信息。

好了,这一节的内容就到这里。记住,调试 STUN/TURN 没有捷径,但用好 stunclient 这个工具,能让你少走很多弯路。下次遇到连接问题,别急着改代码,先跑一遍 stunclient 试试。

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