NAT 穿透详解:STUN / TURN / ICE

NAT 穿透详解:STUN / TURN / ICE

WebRTC 要实现 P2P,最大的障碍是 NAT。大部分设备都在路由器后面,没有公网 IP,怎么直连?这篇讲 NAT 是什么、STUN 怎么发现公网地址、TURN 怎么中继、ICE 怎么整合两者选最优路径。

大家好,我是黒漂技术佬。

做 WebRTC,NAT 穿透是绕不开的话题。为什么有时候视频通话连不上?为什么同一个 Wi-Fi 下可以,换个网络就不行?为什么需要 TURN 服务器?

这篇把 NAT、STUN、TURN、ICE 讲明白:原理是什么、怎么工作、怎么配置、常见问题怎么排查。


一、NAT 是什么?

全称

Network Address Translation,网络地址转换。

为什么要有 NAT?

IPv4 地址不够用,大家共用一个公网 IP。路由器做地址转换:

复制代码
内网设备        路由器(NAT)        公网
192.168.1.10 →  公网IP:端口  →  互联网
192.168.1.11 →  公网IP:端口  →  互联网

内网设备只有私网 IP,外面的设备直接访问不到。

NAT 对 P2P 的影响

两台都在 NAT 后面的设备,互相不知道对方的公网地址和端口,直接连不上。

这就是 WebRTC 需要 STUN/TURN/ICE 的原因------解决 NAT 穿透问题。


二、NAT 的四种类型

不同类型的 NAT,穿透难度不一样。

1. 完全锥型 NAT(Full Cone)

一个内网端口映射到一个公网端口,任何外部地址都能通过这个公网端口发数据进来。

  • 最容易穿透
  • 现在比较少见

2. 受限锥型 NAT(Restricted Cone)

映射也是固定的,但只有你主动联系过的外部地址,才能发数据回来。

  • 中等难度
  • 比较常见

3. 端口受限锥型 NAT(Port Restricted Cone)

比受限锥更严格,不仅限制 IP,还限制端口。只有你发过数据的那个 IP+端口,才能发回来。

  • 难度较大
  • 也比较常见

4. 对称型 NAT(Symmetric)

每个不同的目标地址,分配不同的公网端口。你给 A 发用一个端口,给 B 发用另一个端口。

  • 最难穿透,STUN 基本打不通
  • 需要 TURN 中继
  • 企业级 NAT、运营商级 NAT(CGN)很多是对称型

穿透难度

复制代码
完全锥 < 受限锥 < 端口受限锥 < 对称型

前三种用 STUN 大概率能打通,对称型基本打不通,得上 TURN。


三、STUN 服务器

全称

Session Traversal Utilities for NAT,NAT 会话穿透工具。

作用

帮你发现自己的公网 IP 和端口。

工作原理

复制代码
内网设备                    STUN服务器
   │                           │
   │─── 发个包给STUN ─────────▶│
   │                           │  看到你的源IP和端口
   │◀── 返回你的公网地址 ──────│
   │                           │

设备给 STUN 服务器发个包,STUN 服务器从包里看到源 IP 和端口,就是你的公网地址,然后告诉设备。

这样你就知道自己在公网上是什么地址了,然后通过信令告诉对方。

STUN 能解决什么?

  • 发现公网 IP 和端口(生成 srflx 类型的 ICE 候选)
  • 大部分家用路由器能穿透(锥型 NAT)

STUN 不能解决什么?

  • 对称型 NAT 打不通
  • 双重 NAT(路由器后面又接路由器)可能打不通
  • 防火墙禁了 UDP 的话不行

常用的公共 STUN

复制代码
stun:stun.l.google.com:19302
stun:stun1.l.google.com:19302
stun:stun.qq.com:3478

测试用公共的就行,生产环境建议自己搭或者用商用服务。

STUN 配置

javascript 复制代码
const pc = new RTCPeerConnection({
  iceServers: [
    { urls: 'stun:stun.example.com:3478' }
  ]
});

四、TURN 服务器

全称

Traversal Using Relays around NAT,用中继穿透 NAT。

作用

STUN 打不通的时候,走 TURN 服务器中继------数据发给 TURN,TURN 转发给对方。

复制代码
A ────▶ TURN服务器 ────▶ B

什么时候需要 TURN?

  • 对称型 NAT
  • 企业防火墙限制严格
  • 双重 NAT
  • 一方在 IPv4 一方在 IPv6

大概 10-20% 的场景需要走 TURN,具体看用户网络环境。

TURN 和 STUN 的区别

STUN TURN
作用 发现公网地址 中继转发数据
流量 很少(只有信令) 所有媒体流量都过服务器
成本 高(带宽成本大)
优先级 高(优先用) 低(兜底用)

TURN 服务器实现

  • coturn:最主流的开源 TURN 服务器,C 语言写的,性能好
  • restund:另一个开源实现
  • 商用服务:Twilio、Xirsys 等

生产环境一般用 coturn 自己搭。

TURN 配置

javascript 复制代码
const pc = new RTCPeerConnection({
  iceServers: [
    { urls: 'stun:stun.example.com:3478' },
    {
      urls: 'turn:turn.example.com:3478',
      username: 'username',
      credential: 'password'
    }
  ]
});

TURN 需要用户名密码认证,防止被滥用。

TURN 的传输协议

  • UDP:默认,延迟低
  • TCP:UDP 被封的时候用,延迟高一点
  • TLS-TCP:加密的 TCP,更难被封

可以都配上,自动选能用的。


五、ICE:整合 STUN 和 TURN

全称

Interactive Connectivity Establishment,交互式连接建立。

作用

ICE 不是一个具体协议,而是一个框架------整合 STUN 和 TURN,自动找出两端之间最好的连通路径。

ICE 怎么做?

1. 收集候选地址

每个端收集所有可能的地址:

  • host 候选:本机所有网卡的内网地址
  • srflx 候选:STUN 服务器反射的公网地址
  • relay 候选:TURN 中继地址
2. 交换候选

通过信令把自己的候选发给对方。

3. 候选配对

两边的候选两两配对,形成候选对。

4. 连通性检查

按优先级从高到低,每个候选对发探测包,看能不能通。

优先级:host > srflx > relay

5. 选定最佳路径

找到第一个能连通的配对,就用它传输数据。同时继续检查,找到更好的就切换(ICE 重启/提名)。

ICE 状态

  • new:初始
  • checking:正在检查配对
  • connected:找到可用连接了(可能还在找更好的)
  • completed:检查完了,确定了最佳路径
  • failed:所有配对都不行,连不上
  • disconnected:连接断了(可能暂时的,会重试)
  • closed:关闭

Trickle ICE(逐滴 ICE)

传统 ICE:收集完所有候选再发给对方,慢。

Trickle ICE:收集到一个发一个,边收集边发,连接建立更快。

WebRTC 默认就是 Trickle ICE,所以 onicecandidate 事件会触发多次。


六、ICE 候选详解

候选格式

复制代码
candidate:foundation component transport priority ip port type ...

例子:

复制代码
candidate:1234567890 1 udp 2122260223 192.168.1.100 55555 typ host generation 0

三种类型对比

类型 全称 来源 延迟 成本 优先级
host 主机候选 本机网卡 最低 0 最高
srflx 服务器反射候选 STUN
relay 中继候选 TURN 最高 最低

ICE 优先用延迟最低、成本最低的路径,实在不行才走 TURN。

组件(Component)

  • 1 = RTP(媒体数据)
  • 2 = RTCP(控制信息)

现在一般用 rtcp-mux,RTP 和 RTCP 共用一个端口,只有 component 1。


七、实际部署建议

1. STUN 和 TURN 都配上

生产环境一定要同时配 STUN 和 TURN:

  • STUN 负责大部分场景(P2P,省带宽)
  • TURN 负责兜底(打不通的时候用)

2. TURN 服务器部署位置

  • 选多线 BGP 机房,不同运营商访问都快
  • 部署在多个地域,用户就近接入
  • 带宽要够,TURN 是吃带宽的

3. 安全配置

  • TURN 一定要开认证,不然被人盗用刷流量
  • 定期换密码
  • 限制速率,防止攻击

4. 监控

  • 监控 TURN 带宽使用
  • 统计 P2P 成功率和 TURN 比例
  • TURN 比例太高的话,检查是不是 STUN 有问题

5. 自己搭还是用商用?

  • 小流量:自己搭 coturn,成本低
  • 大流量/全球化:考虑商用服务,省运维

八、coturn 快速搭建

安装(Ubuntu)

bash 复制代码
apt install coturn

配置

编辑 /etc/turnserver.conf

复制代码
# 监听端口
listening-port=3478

# 中继端口范围
min-port=49152
max-port=65535

# 认证
lt-cred-mech
user=username:password

# 域名
realm=turn.example.com

# 外网 IP(云服务器要填)
external-ip=你的公网IP

# 日志
log-file=/var/log/turnserver.log
verbose

启动

bash 复制代码
systemctl start coturn
systemctl enable coturn

防火墙

开放 UDP 3478 端口,以及中继端口范围(49152-65535/udp)。

测试

用在线 WebRTC 测试工具,或者自己写代码测一下能不能拿到 relay 候选。


九、连接失败排查

步骤 1:看 ICE 状态

javascript 复制代码
pc.oniceconnectionstatechange = () => {
  console.log('ICE state:', pc.iceConnectionState);
};
  • 一直 checking:候选没交换完,或者都不通
  • failed:所有候选都失败了

步骤 2:看收集到哪些候选

javascript 复制代码
pc.onicecandidate = e => {
  if (e.candidate) {
    console.log('候选:', e.candidate.type, e.candidate.address);
  }
};
  • 只有 host 候选:STUN 没配置或没通
  • 没有 relay 候选:TURN 没配置或认证失败

步骤 3:检查 STUN/TURN 配置

  • 地址对不对?
  • 端口对不对?
  • TURN 的用户名密码对不对?
  • 防火墙有没有开放 UDP 端口?

步骤 4:用测试工具验证

网上搜「WebRTC test」「Trickle ICE test」,有在线工具可以单独测 STUN 和 TURN。

常见失败原因

  1. 防火墙封了 UDP:只能走 TCP TURN
  2. 对称型 NAT + 对称型 NAT:基本打不通,必须 TURN
  3. TURN 中继端口没开:拿到了 relay 候选但数据传不过去
  4. 云服务器没配 external-ip:coturn 拿不到公网 IP,中继失败
  5. 双重 NAT:穿透难度大,可能需要 TURN

十、常见坑

坑 1:只配 STUN 不配 TURN

测试的时候都在同一个 Wi-Fi 下没问题,上线后一堆用户连不上。一定要配 TURN 兜底。

坑 2:TURN 带宽没预估

走 TURN 的用户,所有音视频流量都过服务器,人多了带宽爆炸。提前预估,监控带宽。

坑 3:TURN 没开认证

公网 TURN 不设密码,分分钟被扫到盗用,账单爆炸。

坑 4:云服务器没开中继端口范围

TURN 不止用 3478,中继数据用的是随机端口,要开放整个端口范围。

坑 5:coturn 没配 external-ip

云服务器内网网卡上是内网 IP,coturn 不知道公网 IP,中继会失败。一定要配置 external-ip。

坑 6:ICE 失败就放弃了

ICE 进入 failed 状态,可以尝试 ICE restart 重新协商,说不定就通了。


十一、本篇小结

  • NAT:地址转换,内网设备共用公网 IP,P2P 的主要障碍
  • NAT 分四类:完全锥、受限锥、端口受限锥、对称型,穿透难度递增
  • STUN:发现公网地址,解决锥型 NAT 的穿透,成本低
  • TURN:中继转发,兜底方案,所有情况都能通,但带宽成本高
  • ICE:整合 STUN+TURN,自动收集候选、配对检查、选最优路径
  • 候选优先级:host(内网直连)> srflx(STUN公网)> relay(TURN中继)
  • 生产环境 STUN 和 TURN 都要配,P2P 优先,TURN 兜底
  • 连接失败排查:看 ICE 状态 → 看候选 → 检查配置 → 测服务器

下一篇讲音视频编解码:VP8/VP9/H.264/Opus 都是什么、怎么选、怎么配置。

我是黒漂技术佬。

相关推荐
精明的身影2 小时前
网络计划WebApp求解:融合Python与AI决策的项目管理系统
网络·python·web app
范什么特西2 小时前
网络代理问题
java·linux·服务器
姚不倒3 小时前
F5 SSL Profile 证书卸载深入篇
运维·网络协议·负载均衡·ssl·f5
utf8mb4安全女神3 小时前
【Redis数据库】哨兵集群/redis集群/安装配置/主从复制/数据持久化操作/数据结构/安全限制/PHP redis/
linux·服务器·数据结构·数据库·redis·缓存
智商偏低3 小时前
Windows Nginx 完整安装 + 启动教程
运维·nginx
Zk.Sun3 小时前
Linux设置触屏双击距离容差
linux·运维·数据库
Let's Chat Coding3 小时前
对称密钥认证:主机和设备共享同一把密钥
运维·服务器·网络
bukeyiwanshui3 小时前
20260622 安装配置ubuntu
linux·运维·ubuntu
写代码的学渣4 小时前
Linux 安装 Swap 交换分区大小标准(通用 + 生产服务器 + 个人 PC)
linux·运维·服务器
tonydf4 小时前
.NET 项目集成可观测性:从架构思考到落地实践
运维·后端