WebRTC在对称NAT场景下无法穿透问题解析和方案
什么是WebRTC?
是一种支持浏览器之间实时音视频通信和数据传输的开放标准技术,无需安装插件或第三方软件。它被广泛应用于视频会议、在线教育、远程医疗、直播互动等场景。
核心组件
- MediaStream(媒体流)
获取用户的摄像头/麦克风 - RTCPeerConnection(点对点连接)
负责建立和管理音视频通信通道;处理编解码、带宽自适应、NAT 穿透等 - RTCDataChannel(数据通道)
支持低延迟的任意数据传输
交互步骤
以A、B两个设备作为例子,A呼叫B
- 初始化 PeerConnection
A 和 B 各自在本地创建 RTCPeerConnection 对象,此时只是设定服务相关代码配置,并无网络通信。const pc = new RTCPeerConnection({ iceServers: [ { urls: "stun:stun.l.google.com:19302" }, { urls: "turn:your-turn.com:3478", username: "...", credential: "..." } ] }); - A 创建 Offer(生成 SDP)
- 收集所有 ICE candidate(host / srflx / relay)
- host:本机局域网地址(如 192.168.0.2)
- srflx:通过 STUN 获取的公网反射地址(如 100.100.100.100:50000)
- relay:通过 TURN 获取的中继地址(如 200.200.200.200:50001)
- 列出支持的音视频编解码器
- 生成一个 SDP Offer 文本
- 通过信令服务器将 SDP Offer 发送给 B
- 收集所有 ICE candidate(host / srflx / relay)
- B 收到 Offer,创建 Answer(生成 SDP)
- 解析 A 的能力
- 选择双方都支持的编解码器
- 收集自己的 ICE candidate(host / srflx / relay)
- 生成 SDP Answer 文本
- B 通过信令服务器将 SDP Answer 发回给 A
- ICE 候选地址交换(Trickle ICE)
- 在步骤2、3之后,浏览器会持续发现新的 ICE candidate
- 在连通性检查中动态发现的地址叫prflx
- 每当发现一个新 candidate,A/B 将每个 candidate 单独通过信令服务器发送给对方
- 在步骤2、3之后,浏览器会持续发现新的 ICE candidate
- ICE 连接检查
- 双方拿到对方的 candidate 后,开始 ICE 配对测试
- 尝试所有组合:A 的 candidate × B 的 candidate
- 发送 STUN binding request 测试连通性
- 优先尝试 host → srflx(直连),如果失败,自动降级到 relay(中继)
- 一旦某对地址能互通(如 A 的 relay ↔ B 的 srflx),就选定该路径
- 只有WebRTC服务发起方能主动发起连通性检查
- A发送 STUN Binding Request 中包含一个 transaction ID
- C收到 Request后,用STUN Binding Request的 transaction ID 回复 STUN Binding Response
- A收到 STUN Binding Response,WebRTC 引擎验证 transaction ID 匹配
- ICE 状态变为 connected → 媒体流开始传输
- 建立 DTLS 加密通道 → SRTP 媒体流开始传输
- 双方拿到对方的 candidate 后,开始 ICE 配对测试
- 媒体流传输
- 音视频数据通过选定的 UDP 路径直接传输(P2P)或经 TURN 中继
未使用Coturn案例
A设备是一台4G移动终端,B设备是一台服务器,C设备是一台PC主机,B、C在一个局域网内,此局域网有公网IP。
这里使用的1000、4000端口是简化模型的端口号,在实际过程中,STUN 查询(UDP)、信令连接(TCP)、媒体传输(UDP)在发送数据包的时候都是创建了不同的高端口用来发送和接收数据。
这里假设:
- A:内网IP:10.0.0.2,WebRTC随机端口:1000,出口公网IP:100.0.0.2,Wi-Fi连接宽带IP:150.0.0.2
- B:内网IP:192.0.0.2,公网IP:200.0.0.2,信令服务器WebSocket端口:3000
- C:内网IP:192.0.0.3,公网IP:200.0.0.2,WebRTC随机端口4000
- D:STUN服务器IP:50.0.0.2:3478
场景1:A设备连接普通宽带
- A设备发起对C设备的视频&语音通信,可以正常通信。
- 步骤分析:
- 当 A 和 C 分别连接信令服务器(如 WebSocket)时,会建立一条 出站 TCP 连接。
- A (10.0.0.2:1000) → 公网出口 (100.0.0.2:2000) → 信令服务器 (200.0.0.2:3000)
- C (192.0.0.3:4000) → 公网出口 (200.0.0.2:4000) → 信令服务器 (200.0.0.2:3000)
- A向C发起请求的时候,其实是向信令服务器发送了自己的网络情况,让信令服务器把自己的信息发给C,然后C接收到了A的信息,也把自己的网络信息通过信令服务器发给了A。
- 等A接收到以后,A和C都往对方的公网IP发送连通请求包,这样又是在自己的网关端创建了A和C的NAT通道。
- A (10.0.0.2:1000) → 公网出口 (100.0.0.2:2000) → C 公网出口 (200.0.0.2:4000)
- C (192.0.0.3:4000) → 公网出口 (200.0.0.2:4000) → A 公网出口 (100.0.0.2:2000)
- 等着A和C完成 ICE 连通性检查,就连接成功了。
sequenceDiagram participant A participant Sig as 信令服务器 participant C A->>Sig: WebSocket 连接(创建 NAT 通道1) C->>Sig: WebSocket 连接(创建 NAT 通道2) A->>Sig: 发送 offer + candidates Sig->>C: 转发 C->>Sig: 发送 answer + candidates Sig->>A: 转发 A->>C: UDP STUN Request(创建 NAT 通道3) C->>A: UDP STUN Request(创建 NAT 通道4) Note over A,C: 双方收到 STUN Response ICE 连通性检查成功 P2P 连接建立! - 当 A 和 C 分别连接信令服务器(如 WebSocket)时,会建立一条 出站 TCP 连接。
场景2:A设备使用4G网络
- A设备发起对C设备的视频&语音通信,B、C可以收到通信请求,但是无法连接。
- 核心原因:
- 由于 4G 网络通常采用对称型 NAT(Symmetric NAT),A 设备访问不同目标(STUN 服务器 vs C 设备)时,会被分配不同的公网端口。因此,A 通过 STUN 获取的公网地址(100.0.0.2:2000)仅对 STUN 服务器有效,C 设备向该地址发包会被运营商丢弃,导致 ICE 连通性检查失败,无法建立 P2P 连接。
- 步骤分析:
- A设备对C设备的公网地址200.0.0.2发起视频&语音通信。
- 此时处于WebRTC的步骤2收集ICE candidate阶段,A设备需要调用STUN服务查询公网IP和端口,所以运营商网关分配了一个100.0.0.2:2000外网端口,A设备(10.0.0.2:1000)通过此端口向STUN服务器发送请求:从运营商网关(100.0.0.2:2000)发送到STUN服务器(50.0.0.2:3478)。
- 运营商接收到A设备发起的请求,在NAT表中记录了一条:将STUN服务器(50.0.0.2:3478)发送向运营商网关(100.0.0.2:2000)的数据包转发给A设备(10.0.0.2:1000)。
- STUN服务器收到运营商网关(100.0.0.2:2000)的数据包以后,向运营商网关(100.0.0.2:2000)发送了一个响应包,告诉请求方的公网IP地址是多少。
- 运营商网关(100.0.0.2:2000)收到了STUN服务器(50.0.0.2:3478)的响应包,从NAT表中查询到这个数据包应该转发给A设备(10.0.0.2:1000)。
- A设备接收到了STUN服务器的响应包,于是把100.0.0.2:2000当作自己的公网IP地址,然后封装到SDP Offer中。
- 接着A设备(10.0.0.2:1000)会把SDP Offer包通过信令服务器WebSocket服务(200.0.0.2:3000)发送给C设备(200.0.0.2:4000)。
- 运营商网关收到了10.0.0.2:1000 → 200.0.0.2:3000的发包请求,由于100.0.0.2:2000的端口被50.0.0.2:3478使用过了,根据对称NAT的安全策略要求,所以运营商网关为这个请求创建了新的端口100.0.0.2:2001,然后在NAT表上记录了一条:将信令服务器WebSocket服务(200.0.0.2:3000)发送给运营商网关(100.0.0.2:2001)的数据包转发给A设备(10.0.0.2:1000),之后数据包顺着100.0.0.2:2001发送了出去。
- 信令服务器WebSocket服务收到A设备的SDP Offer包以后,将包转发给了C设备。
- C设备收到A设备的SDP Offer包,解析后知道了A设备的公网IP是100.0.0.2:2000,于是开始准备自己的SDP Answer包,也执行了一遍STUN服务器请求,将STUN服务器返回的C设备的公网IP(200.0.0.2:4000)。
- C设备(200.0.0.2:4000)将SDP Answer包发送给信令服务器WebSocket服务(200.0.0.2:3000),信令服务器检查到是C设备对A设备的回包,所以信令服务器将SDP Answer包发往A设备请求时来的运营商网关(100.0.0.2:2001)。
- 运营商网关(100.0.0.2:2001)接收到了信令服务器WebSocket服务(200.0.0.2:3000)的数据包,检查NAT表发现需要将数据转发给A设备(10.0.0.2:1000),所以将SDP Answer包转发给了A设备。
- A设备接收到C设备的SDP Answer包,知道了C设备的公网IP是200.0.0.2:4000,所以开始WebRTC的ICE 连通性检查阶段(步骤5),通过尝试A设备和C设备的候选地址组合,尝试建立连接;C设备在发出SDP Answer包的同时,也开始尝试C设备和A设备的候选地址组合,尝试建立连接。
- A设备(10.0.0.2:1000)拿着C设备的公网200.0.0.2:4000尝试建立连接,运营商网关发现这又是一个新的目标IP,所以根据对称NAT的安全策略要求,创建了新的端口100.0.0.2:2002,然后在NAT表中创建了一条:将C设备(200.0.0.2:4000)发送给运营商网关(100.0.0.2:2002)的数据包转发给A设备(10.0.0.2:1000),之后把测试连接数据包发送给C设备。
- C 设备尝试向 A 报告的 srflx 地址 100.0.0.2:2000 发送 STUN Binding Request,但该端口仅对 STUN 服务器 50.0.0.2:3478 开放。由于对称 NAT 的端口绑定策略,来自 200.0.0.2:4000 的数据包被运营商网关视为非法,直接丢弃。而 A 向 C 发起的连接使用的是新端口 100.0.0.2:2002,双方端口不匹配,导致双向打洞失败。
- 从而导致设备A和设备C无法构建P2P连接。
sequenceDiagram title WebRTC 连接失败:A(4G, 对称NAT) → C(公网可达) participant A as A设备<br/>(10.0.0.2:1000) participant GW as 运营商网关<br/>(对称NAT) participant STUN as STUN服务器<br/>(50.0.0.2:3478) participant Sig as 信令服务器<br/>(200.0.0.2:3000) participant C as C设备<br/>(192.0.0.3 → 公网200.0.0.2:4000) Note over A,GW: 阶段1: A收集ICE候选地址(调用STUN) A->>GW: 出站UDP → STUN GW->>STUN: 转发 (源: 100.0.0.2:2000) Note right of GW: NAT表:<br/>10.0.0.2:1000 ↔ 100.0.0.2:2000<br/>仅允许50.0.0.2:3478回包 STUN-->>GW: 响应 (目标: 100.0.0.2:2000) GW-->>A: 转发响应 A->>A: 记录 candidate: srflx 100.0.0.2:2000 Note over A,Sig: 阶段2: 通过信令交换SDP A->>GW: 出站TCP → 信令服务器 GW->>Sig: 转发 (源: 100.0.0.2:2001) Note right of GW: 对称NAT!<br/>新目标 → 新端口2001<br/>NAT表新增:<br/>10.0.0.2:1000 ↔ 100.0.0.2:2001<br/>仅允许200.0.0.2:3000回包 Sig->>C: 转发 SDP Offer<br/>(含A的candidate: 100.0.0.2:2000) C->>C: 收集自身candidate<br/>(如 200.0.0.2:4000) C->>Sig: 发送 SDP Answer Sig->>GW: 转发 Answer 到 100.0.0.2:2001 GW->>A: 转发 Answer Note over A,C: 阶段3: ICE连通性检查(打洞尝试) A->>GW: 出站UDP → C (200.0.0.2:4000) GW->>C: 转发 (源: 100.0.0.2:2002) Note right of GW: 又一新目标 → 新端口2002!<br/>NAT表新增:<br/>10.0.0.2:1000 ↔ 100.0.0.2:2002<br/>仅允许200.0.0.2:4000回包 C->>C: 尝试向A报告的地址发包<br/>(100.0.0.2:2000) C->>GW: UDP → 100.0.0.2:2000 Note right of GW: ❌ 匹配失败!<br/>端口2000只接受<br/>50.0.0.2:3478的回包<br/>来自200.0.0.2:4000的包被丢弃! Note over GW,C: 结果: 双向打洞失败 Note over A,C: A用2002发包,C往2000发包 → 端口不匹配! - 与场景1的区别
- 因为设备A是在普通宽带场景下,运营商执行的是锥形NAT策略,A设备可以先通过运营商网关(100.0.0.2:2000)的2000端口发送请求,然后再次使用2000端口发送给WebSocket服务(200.0.0.2:3000),等着A设备与C设备通信的时候,依旧使用的是运营商网关的2000端口,这样就实现了P2P直连。
使用Coturn案例
解决办法可见【Docker - 使用Coturn实现WebRTC稳定连接】
场景
这里的模型使用更精确一些的场景:A设备是一台4G移动终端(对称NAT环境)、B网络是两台服务器(具有公网IP,分别安装信令服务和STUN/TURN服务)、C设备是一台台式机(锥形NAT环境),假设:
- A设备:内网IP:10.0.0.2,操作系统分配的临时端口范围:50000–51000,运营商4G网关IP:20.0.0.2,公网端口号随内网端口号改变
- B网络:信令服务器公网:50.0.0.2:1000(TCP),STUN/TURN服务公网:50.0.0.2:3478(UDP),Coturn分配中继端口号范围:55000–56000(UDP)
- C设备:内网IP:192.0.0.2,操作系统分配的临时端口范围:60000–61000,家庭路由器公网IP:100.0.0.2,公网端口号随内网端口号改变
步骤
- A设备、C设备配置信令服务器地址、Coturn服务器地址,并启动应用程序,此时两个设备分别向信令服务器创建了两条 NAT 映射,并成功在信令服务器完成了注册、创建了连接。
- A (10.0.0.2:50000/TCP) → 运营商4G网关 (20.0.0.2:50000/TCP) → 信令服务器 (50.0.0.2:1000/TCP)
- C (192.0.0.2:60000/TCP) → 家庭路由器 (100.0.0.2:60000/TCP) → 信令服务器 (50.0.0.2:1000/TCP)
- A设备发起了对C设备的连接请求,先开始探查自身网络情况,收集 ICE candidates,目前能够确定的是内网IP:10.0.0.2、STUN服务器:50.0.0.2:3478(UDP),TURN服务器:50.0.0.2:3478(UDP)。向 STUN 服务器发送请求检查外网端口,向 TURN 服务器发送请求获取中继地址。
- A (10.0.0.2:50001/UDP) → 运营商4G网关 (20.0.0.2:50001/UDP) → STUN服务器 (50.0.0.2:3478/UDP)
- A (10.0.0.2:50002/UDP) → 运营商4G网关 (20.0.0.2:50002/UDP) → TURN服务器 (50.0.0.2:3478/UDP)
- STUN服务器检测到A设备的公网地址是 “20.0.0.2:50001/UDP”,TURN服务器为A设备申请了临时中继地址 “50.0.0.2:55001/UDP”。
- A设备将收集到的 ICE candidate 等信息生成 SDP Offer,通过已建立的 WebSocket 连接发送给信令服务器,目标是 C 设备。
- host:10.0.0.2:50001/UDP
- srflx:20.0.0.2:50001/UDP
- relay:50.0.0.2:55001/UDP
- A (10.0.0.2:50000/TCP) → 运营商4G网关 (20.0.0.2:50000/TCP) → 信令服务器 (50.0.0.2:1000/TCP)
- 信令服务器通过已建立的 WebSocket(TCP)连接,将 A 设备的 SDP Offer 转发给 C 设备。
- 信令服务器 (50.0.0.2:1000/TCP) → 家庭路由器 (100.0.0.2:60000/TCP) → C (192.0.0.2:60000/TCP)
- C设备收到了 A 设备的 SDP Offer,开始探查自身网络情况,收集 ICE candidates,目前能够确定的是内网IP:192.0.0.2、STUN服务器:50.0.0.2:3478(UDP),TURN服务器:50.0.0.2:3478(UDP)。向 STUN 服务器发送请求检查外网端口,向 TURN 服务器发送请求获取中继地址。
- C (192.0.0.2:60001/UDP) → 家庭路由器 (100.0.0.2:60001/UDP) → STUN服务器 (50.0.0.2:3478/UDP)
- C (192.0.0.2:60002/UDP) → 家庭路由器 (100.0.0.2:60002/UDP) → TURN服务器 (50.0.0.2:3478/UDP)
- STUN服务器检测到C设备的公网地址是 “100.0.0.2:60001/UDP”,TURN服务器为C设备申请了临时中继地址 “50.0.0.2:55002/UDP”。
- C设备将收集到的 ICE candidate 等信息生成 SDP Answer,通过已建立的 WebSocket 连接发送给信令服务器,目标是 A 设备。
- host:192.0.0.2:60001/UDP
- srflx:100.0.0.2:60001/UDP
- relay:50.0.0.2:55002/UDP
- C (192.0.0.2:60000/TCP) → 家庭路由器 (100.0.0.2:60000/TCP) → 信令服务器 (50.0.0.2:1000/TCP)
- 信令服务器通过已建立的 WebSocket(TCP)连接,将 C 设备的 SDP Answer 转发给 A 设备。
- 信令服务器 (50.0.0.2:1000/TCP) → 运营商4G网关 (20.0.0.2:50000/TCP) → A (10.0.0.2:50000/TCP)
- A设备 和 C设备 已交换完整 SDP,下面进入 ICE 连通性检查。A设备生成ICE候选对,依次发送检查。总共有3x3=9种组合方式,但是因为两个设备不在同一个局域网内,所以所有host的方式都是不通的。且因为A设备是对称NAT网络,所以单、双srflx方式也不可靠,这种网络机构下,唯一可靠的就是双relay,这是必然通的组合方式。
A 的 candidate C 的 candidate 组合示例 host: 10.0.0.2host: 192.0.0.2❌ 内网地址,无法互通 host: 10.0.0.2srflx: 100.0.0.2:60001❌ A 的 host 无法被 C 访问 srflx: 20.0.0.2:50001srflx: 100.0.0.2:60001⚠️ 理论可行,但 A 是对称 NAT → 实际失败 relay: 50.0.0.2:55001host / srflx ✅ C 可向 A 的 relay 发包 host / srflx relay: 50.0.0.2:55002✅ A 可向 C 的 relay 发包 relay: 50.0.0.2:55001relay: 50.0.0.2:55002✅ 双中继(最可靠) sequenceDiagram participant A participant Coturn participant C Note over A,C: 双方已交换 SDP A->>C: ICE Check 1: A.srflx → C.srflx (失败) A->>Coturn: ICE Check 2: A → Coturn → C.srflx (可能失败) A->>Coturn: ICE Check 3: A → Coturn:55002 (成功!) Coturn->>C: 转发 STUN Binding Request C->>Coturn: STUN Response Coturn->>A: 转发 Response A->>A: 确认 (A.relay, C.relay) 连通! A->>Coturn: 开始发送媒体流 (RTP) C->>Coturn: 开始发送媒体流 (RTP) - 这里只取双srflx、A(relay)+C(srflx)和双relay三种检查情况来分析为什么最终会选择双relay。
- 双srflx情况
- A设备选取了A srflx(20.0.0.2:50001/UDP) + C srflx(100.0.0.2:60001/UDP)方式开始检查,首先A设备使用C设备返回的SDP Answer地址信息,发送STUN Binding Request给C设备的srflx地址。因为C设备的网络环境是锥形NAT,家庭路由器允许来自任意外部IP向已映射端口(100.0.0.2:60001)的入站包。
- A (10.0.0.2:50003/UDP) → 运营商4G网关 (20.0.0.2:50003/UDP) → 家庭路由器 (100.0.0.2:60001/UDP) → C (192.0.0.2:60001/UDP)
- C设备收到A设备的STUN Binding Request包(目标端口60001),从同一socket(192.0.0.2:60001)构造STUN Binding Response,并发往A的源地址(20.0.0.2:50003)。
- C (192.0.0.2:60001/UDP) → 家庭路由器 (100.0.0.2:60001/UDP) → 运营商4G网关 (20.0.0.2:50003/UDP) → ❌ 丢弃
- 由于A设备处于对称NAT环境,运营商4G网关只为特定目标地址创建端口映射。A设备使用50003端口向C设备(100.0.0.2:60001)发包时,虽分配了公网端口50003,且 C设备 的回包地址(100.0.0.2:60001)与 A设备 出站目标地址匹配,但由于 A设备 处于运营商级对称 NAT 后,其网关通常不会为临时 STUN 检查包建立稳定的入站映射,导致回包被丢弃,A设备无法收到STUN Binding Response。
- 丢包可能性1: 运营商 NAT 实现“延迟建表”或“状态机严格”,很多运营商(尤其 4G/5G CGNAT)为了安全和性能,不会在 A 发出第一个包后立即开放入站通道,而是等待“完整事务”或超时后才建立双向映射
- 丢包可能性2: 运营商可能对 UDP 流量做深度检测,如果包不是 RTP/RTCP(如 STUN),可能被归类为“控制信令”,而 CGNAT 可能只对已知媒体端口开放双向通道
- 4G 运营商的 CGNAT 极其严格,且常有上述“延迟建表”行为。运营商优先考虑 安全性 和 资源节省,而非 P2P 连通性。
- 因A设备无法收到C设备的响应,双srflx路径被判定为不通。这与未使用Coturn的案例类似;不同的是,使用Coturn时ICE会继续尝试relay候选对,最终通过双中继建立连接。再最开始就否定了host方式连接,在这里也否定了A设备用srflx方式连接的可能。
- A设备选取了A srflx(20.0.0.2:50001/UDP) + C srflx(100.0.0.2:60001/UDP)方式开始检查,首先A设备使用C设备返回的SDP Answer地址信息,发送STUN Binding Request给C设备的srflx地址。因为C设备的网络环境是锥形NAT,家庭路由器允许来自任意外部IP向已映射端口(100.0.0.2:60001)的入站包。
- A(relay)+C(srflx)情况
术语解释
SDP
Session Description Protocol,会话描述协议。是 WebRTC 和许多实时通信系统中用于协商媒体通信参数的核心文本格式。
- SDP 的本质:一份“通信能力清单 + 联系方式”
我的 IP 和端口是多少?(网络层)
我支持 H.264 还是 VP8 视频?(编解码)
音频用 Opus 还是 G.711?
是否支持屏幕共享?
如何加密?(DTLS/SRTP)
锥形 NAT(宽松 NAT)
- 分类
- 完全锥形 NAT(Full Cone):允许任何外部 IP 发包进来
- 受限锥形 NAT(Restricted Cone):只允许曾通信过的外部 IP发包进来
- 端口受限锥形 NAT(Port-Restricted Cone):只允许曾通信过的外部 IP + 端口发包
- 特点
- 同一个内网 IP:Port,无论访问哪个外部地址,映射的公网端口是固定的。
- STUN 能正确获取公网地址(srflx candidate),双方同时向对方公网地址发包(“打洞”),即可建立直连。
- 使用场景
- 家庭宽带
- 普通企业NAT
对称 NAT
- 特点
- 同一个内网 IP:Port,访问不同外部目标时,会分配不同的公网端口!
- srflx candidate 无法用于直连,必须依赖 TURN 中继(relay candidate)
- 构成
每个 (内网IP, 内网Port, 目标IP, 目标Port) 四元组 → 唯一 (公网IP, 公网Port) 映射 - 使用场景
- 企业防火墙
- 校园网
- 4G/5G 网络
- 云服务器
ICE
是一套用于建立端到端网络连接的标准化框架,尤其用于解决 NAT(网络地址转换) 和 防火墙 带来的通信障碍
- 核心思想
不依赖单一地址,而是收集所有可能的网络地址(本地、公网、中继)。
尝试所有可能的地址组合(称为 candidate pairs)。
通过 连通性检查(Connectivity Checks) 找出能通的路径。
选择延迟最低、质量最好的路径进行通信。 - 技术
- STUN:获取公网反射地址(srflx candidate)
- TURN:获取中继地址(relay candidate),用于保底通信
- SDP:在信令阶段交换 ICE 候选地址
- UDP/TCP:实际传输协议
STUN
STUN 是一种轻量级协议,用于帮助客户端发现自己的公网 IP 地址和端口(即“NAT 映射后的地址”),并检测 NAT 类型
- 工作原理
- 客户端向公网 STUN 服务器发送请求。
- STUN 服务器看到请求来自某个公网 IP:Port(例如 100.100.100.100:50000)。
- 服务器将这个公网地址返回给客户端。
- 客户端得知在外网看来是 100.100.100.100:50000。
- 用途
- 获取 srflx(server reflexive)类型的 ICE 候选地址
- 用于 P2P 直连(如果双方 NAT 允许打洞)
- 局限
- 无法穿透对称型 NAT(Symmetric NAT)
- 不提供数据中继,仅用于“地址发现”
TURN
TURN 是一种中继协议,当 P2P 直连失败时,通过 TURN 服务器中转音视频或数据流。
- 工作原理
- 客户端向 TURN 服务器申请一个“中继地址”(如 turn.example.com:50001)
- TURN 服务器分配一个公网 IP 和端口,并告知客户端。
- 双方都将数据发送到该中继地址,由 TURN 服务器转发。
- 用途
- 提供 relay(中继)类型的 ICE 候选地址
- 100% 确保连接成功(即使在对称 NAT 或防火墙严格环境下)
- 缺点
- 消耗服务器带宽和资源(所有流量经过服务器)。
- 增加延迟(非直连)。
- 需要认证和计费管理(防止滥用)。
信令服务器
信令服务器 是 WebRTC 中用于交换连接元数据(metadata) 的中间服务器。它不传输音视频或数据内容,只负责“牵线搭桥”
- 信令
- 网络地址(ICE candidates)
- 媒体能力(音频/视频编码格式、分辨率等)
- 会话控制信息(谁发起、谁应答)
- 为什么要用
- WebRTC 本身 没有内置信令机制。两个浏览器要建立 P2P 连接,必须先知道对方的信令,需要通过一个双方都能访问的第三方服务器传递。
- 传递数据类型
- SDP:描述媒体能力与会话参数
- ICE Candidates:网络候选地址
- 传递流程sequenceDiagram participant A as 浏览器A participant S as 信令服务器 participant B as 浏览器B A->>S: 发送 SDP offer S->>B: 转发 offer B->>S: 发送 SDP answer S->>A: 转发 answer loop ICE候选地址 A->>S: 发送 candidate S->>B: 转发 candidate B->>S: 发送 candidate S->>A: 转发 candidate end A-->>B: WebRTC P2P 连接建立
- 在WebRTC中生效的阶段
第2->5步(见WebCRT交互步骤) - 技术实现
可以用任何双向通信方式实现信令服务器,例如:WebSocket、Socket.IO、MQTT

浙公网安备 33010602011771号