【ZeroRange WebRTC 】STUN 在 WebRTC 中的角色与工作原理(深入指南)
STUN 在 WebRTC 中的角色与工作原理(深入指南)
本文面向前端与实时音视频工程师,系统讲解 STUN(Session Traversal Utilities for NAT)在 WebRTC 中的职责、协议细节、与 ICE 的协作,以及实践部署与排障。
为什么需要 STUN:NAT 与连接穿透的背景
- 绝大多数终端位于内网,使用私有地址(如
192.168.x.x),外界无法直接访问。 - NAT(网络地址转换)对入站流量有过滤与映射策略,不同类型行为差异大:
- Full Cone、Restricted Cone、Port-Restricted Cone、Symmetric NAT(对称NAT)等。
- 结论:多数家庭网络可通过打洞直连;遇到对称 NAT 或严苛防火墙往往需要 TURN 中继。
STUN 是什么:协议概览与要点
- 标准:RFC 5389(核心),与 ICE(RFC 8445)协作,TURN(RFC 5766)补充。
- 核心作用:
- 发现客户端“从外部看”的公网映射地址与端口(server-reflexive address,
srflx)。 - 在 ICE 连通性检查阶段,使用 STUN 消息进行双向探测与路径“提名(nomination)”。
- 发现客户端“从外部看”的公网映射地址与端口(server-reflexive address,
- 典型交互:客户端向 STUN 服务器发送 Binding Request,服务器返回 Binding Success,携带
XOR-MAPPED-ADDRESS(即公网映射)。 - 常见属性(Attributes):
XOR-MAPPED-ADDRESS:服务器观察到的外网 IP/端口。MESSAGE-INTEGRITY:完整性校验(通常基于短期凭据与ice-pwd)。FINGERPRINT:报文校验(CRC32)。ICE-CONTROLLING/ICE-CONTROLLED:决定谁控制候选提名(Offer/Answer角色相关)。USE-CANDIDATE:指示提名使用某候选对为最终路径。
STUN 在 WebRTC 中的职责
- 候选收集:浏览器从多个来源收集候选(
host、srflx、relay),其中srflx依赖 STUN。 - 连通性检查:
- 双端建立候选对矩阵,互发 STUN 请求/响应测试可达性与路径质量。
- 控制方(
ICE-CONTROLLING)在成功路径上使用USE-CANDIDATE提名最终候选对。
- 与 TURN 协作:若所有直连候选(
host/srflx)失败,则回退使用 TURN 的relay候选中继媒体。
ICE 如何把 STUN/TURN 串起来(简述)
- 候选类型:
host:本机地址(现多为 mDNS 名称),延迟最低。srflx:由 STUN 返回的公网映射,适用多数非对称 NAT 场景。relay:TURN 中继地址,适合对称 NAT/企业防火墙,最稳但多一跳。
- 流程关键点:
- 候选优先级排序与配对;并行 STUN 检查缩短建链时间。
- Trickle ICE:候选边收集边上报,缩短首包时间。
- ICE 重启:网络切换时用
createOffer({ iceRestart: true })触发重新探测。
浏览器侧实践:如何使用 STUN(含示例)
- 配置 STUN/TURN:
const pc = new RTCPeerConnection({iceServers: [{ urls: 'stun:stun.l.google.com:19302' },// 生产建议自建或购买可靠 TURN,并启用 TLS/443{ urls: 'turns:turn.example.com:443?transport=tcp', username: 'user', credential: 'pass' }],// 可保持默认;需要更快首包可配合 Trickle ICEiceCandidatePoolSize: 0
});pc.onicecandidate = (e) => {if (e.candidate) {// 通过你的信令通道发送到远端sendToRemote({ type: 'candidate', candidate: e.candidate });}
};// Trickle ICE: 远端逐步添加候选
async function onRemoteCandidate(msg) {await pc.addIceCandidate(msg.candidate);
}
- 行为提示:
- 现代浏览器会用 mDNS 隐藏
host候选中的真实内网 IP,降低隐私暴露。 - 企业网络下更偏好
turns://...:443?transport=tcp,以绕过 UDP 封锁。
- 现代浏览器会用 mDNS 隐藏
常见问题与排障
- 只出现
relay候选:网络严格或对称 NAT;检查 STUN 可达性与端口策略,确保 TURN 已配置且证书有效。 - 候选为空或连接失败:确认信令正确传递 SDP 与候选;调用顺序正确(本地先
setLocalDescription,远端先setRemoteDescription)。 - 黑屏/无声:编解码不匹配、码率限制过低或带宽不足;检查
a=rtpmap/a=fmtp与网络质量。 - IP 隐私:启用默认 mDNS;必要时禁用公开主机候选或使用策略仅允许
relay。
部署与配置建议
- STUN 服务器:
- 开发可用公共
stun:stun.l.google.com:19302;生产建议自建,提升稳定性与可控性。 - 启用 IPv6、部署多地域,提升连通性与降低 RTT。
- 开发可用公共
- TURN 服务器:
- 使用成熟的
coturn,同时启用 UDP+TCP+TLS(turns:)并优先 443 端口。 - 使用临时凭证(TURN REST API 扩展),按分钟签发,避免静态凭证滥用。
- 监控并发与带宽,规划水平扩展与健康检查。
- 使用成熟的
- 客户端策略:
- 开启 Trickle ICE;必要时将
iceTransportPolicy: 'relay'强制中继,确保可用性。 - 网络切换时 ICE 重启;弱网时适当降低视频分辨率与码率。
- 开启 Trickle ICE;必要时将
关键术语速查
- STUN:发现公网映射与连通性检查的工具协议。
- ICE:候选收集、连通性检查与选路的框架。
- TURN:当直连不可达时的中继转发协议与服务。
srflx:由 STUN 返回的服务器反射候选地址类型。- 提名(Nomination):选择最终用于传输的候选对过程。
参考与延伸阅读
- RFC 5389: Session Traversal Utilities for NAT (STUN)
- RFC 8445: Interactive Connectivity Establishment (ICE)
- RFC 5766: Traversal Using Relays around NAT (TURN)
- WebRTC 规格与 MDN:
RTCPeerConnection,iceServers,onicecandidate
附:与 STUN/ICE 相关的 SDP 片段(示意)
v=0
o=- 46117326 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0 1
a=ice-options:trickle
m=audio 9 UDP/TLS/RTP/SAVPF 111 0
c=IN IP4 0.0.0.0
a=mid:0
a=sendrecv
a=rtpmap:111 opus/48000/2
a=setup:actpass
a=fingerprint:sha-256 3A:...:7F
a=ice-ufrag:u1Ab
a=ice-pwd:9kD3...
# 以下为示意性的 ICE 候选
a=candidate:1 1 udp 2122260223 192.168.1.5 54321 typ host
a=candidate:2 1 udp 1686052607 203.0.113.10 62000 typ srflx raddr 192.168.1.5 rport 54321
a=candidate:3 1 udp 1518280447 203.0.113.20 3478 typ relay
总结:STUN 解决“公网身份发现”、在 ICE 中承担“连通性检查”的关键角色;与 TURN 搭配即可在复杂网络保持稳定低延迟的 WebRTC 体验。实践的关键在于合理配置 STUN/TURN、完善的信令、启用 Trickle ICE 与必要的 ICE 重启,以及对编解码与带宽策略的审慎选择。
在 macOS 上进行 STUN 实际测试(操作指南)
目标:验证浏览器是否能从 STUN 获取
srflx候选,以及在不同网络环境下的可达性与表现。
方式一:使用本仓库测试页(快速)
- 打开本目录中的测试页:
stun-test.html(本地访问示例:http://localhost:8001/stun-test.html) - 直接链接(需本地服务器或支持相对路径预览):stun-test.html
- 在输入框填入 STUN/TURN URI(可多个,逗号分隔),如:
stun:stun.l.google.com:19302turns:turn.example.com:443?transport=tcp(如你已配置 TURN)
- 点击“开始测试”,观察表格中收集到的候选:
host:本机/局域网候选(现代浏览器多为 mDNS 名称)。srflx:经 STUN 返回的服务器反射候选,说明公网映射可见。relay:来自 TURN 的中继候选,直连失败时兜底。
- 若只出现
host:- 可能是网络无需 NAT 映射,或 STUN 不可达;更换 STUN 地址或在不同网络环境下测试。
方式二:在 macOS 上自建 STUN(推荐配合云主机)
本机搭建 STUN 仅能提供“局域网视角”,更准确的
srflx映射建议将 STUN 部署到具有公网 IP 的云主机。
- 安装 coturn:
brew install coturn
- 基本配置(仅启用 STUN,最小化示例):
# /opt/homebrew/etc/turnserver.conf (Apple Silicon 路径;Intel 通常为 /usr/local/etc/...)
listening-port=3478
fingerprint
no-tls
no-dtls
simple-log=true
- 启动服务:
turnserver -c $(brew --prefix)/etc/turnserver.conf -v
-
测试:在测试页输入
stun:<你的主机名或公网IP>:3478,开始收集候选。 -
提示与扩展:
- 若你的 Mac 没有公网 IP,本机 STUN 对外网客户端的效果有限;建议把 STUN/ TURN 部署在云主机上进行真实 NAT 映射测试。
- 若需要中继兜底(TURN),在配置中加入认证并启用 TLS/443,例如:
- 增加:
realm=turn.example.com、user=user:pass或启用临时凭证(TURN REST)。 - 开启:
tls-listening-port=5349并正确配置证书(cert/pkey)。 - 浏览器端使用:
turns:turn.example.com:443?transport=tcp。
- 增加:
排障要点
- 无
srflx:检查 STUN 端口 3478(UDP)放行、防火墙策略、网络是否支持外联。 - 使用
turns不通:确认证书链与主机名、SNI、端口 443 放行。 - 候选收集慢:弱网或受限网络下适当等待;减少服务器数量加快收集。
