4.1 候选者收集与连通性检查


文档摘要

4.1 候选者收集与连通性检查 本节摘要:两个躲在 NAT 后面的浏览器,怎么找到彼此?ICE 的答案是:先把各自在网络中的所有可能身份收集齐——本机地址、公网映射地址、中继地址——再两两配对逐个发探测包验证,能通的里面挑最优。本节从 NAT 的行为模型讲到配对与提名机制,让你彻底明白「打洞」这个词背后每一步都在发生什么。 学习目标 阅读完本节,你应当能够: 解释 NAT 为什么会存在,以及它改写地址与端口的两个动作; 区分四类 NAT 行为模型,说出哪两类组合注定无法直连; 说出 host、srflx、prflx、relay 四种候选的来源与优先级规则; 描述连通性检查的配对、探测、提名三步与保活机制; 用浏览器内部工具读懂一次真实通话的候选收集结果。

4.1 候选者收集与连通性检查

本节摘要:两个躲在 NAT 后面的浏览器,怎么找到彼此?ICE 的答案是:先把各自在网络中的所有可能身份收集齐——本机地址、公网映射地址、中继地址——再两两配对逐个发探测包验证,能通的里面挑最优。本节从 NAT 的行为模型讲到配对与提名机制,让你彻底明白「打洞」这个词背后每一步都在发生什么。

学习目标

阅读完本节,你应当能够:

  1. 解释 NAT 为什么会存在,以及它改写地址与端口的两个动作;
  2. 区分四类 NAT 行为模型,说出哪两类组合注定无法直连;
  3. 说出 host、srflx、prflx、relay 四种候选的来源与优先级规则;
  4. 描述连通性检查的配对、探测、提名三步与保活机制;
  5. 用浏览器内部工具读懂一次真实通话的候选收集结果。

一、问题与直觉:地址越来越多,反而更容易连上

直觉上,「连上一个地址」比「连上一堆地址」简单。ICE 的设计恰好相反:它放弃了「猜对唯一地址」的幻想,改为「把可能对的所有地址都列出来试一遍」。原因在 NAT。

家用路由器把整个局域网藏在公网地址后面:内网设备发包出去时,路由器把源地址改写成自己的公网地址并挑一个端口,再把「端口对应哪台内网设备」记进一张映射表;外界的回包只有命中这张表才能被放进来。这个设计让几十台设备共享一个公网地址,也让「外界主动找内网设备」变成了不可能——除非内网设备先向外发过包,在表里留下了痕迹。

打洞正是利用这条规则的边缘:A 和 B 都先向对方发包。A 的包到达 B 的路由器时大概率被丢弃,但 A 路由器的映射表里已经记下了「B 的地址对应我这边一个端口」;B 的包到达 A 的路由器时,恰好命中这条记录,被转发了进来。两边同时扔钥匙,两边先后开门——这就是打洞的全部原理。而「同时」能否成功,取决于两边 NAT 的性格,这就引出行为模型。

二、核心原理:NAT 四型与候选优先级

NAT 的「性格」差异在于映射表的宽容程度。工程上简化为四型:全锥型最慷慨,映射建立后任何外部地址都能借这个端口进来;限制锥型认 IP,只有你发过包的那个对方地址能进来;端口限制锥型认 IP 也认端口,要求更严;对称型最保守——同一个内网端口对不同目的地会用不同的公网端口映射,等于每见一个新朋友就换一张新脸。前三种之间,打洞几乎总能成功;对称型与锥型对打,通常也有一线生机;对称型对对称型,是死局——双方为彼此准备的端口映射都只对对方单向可见,探测包永远错位,只能走 TURN 中继。

ICE 把终端在网络中的身份枚举为四种候选:

候选类型 来源 直连可能性 优先级
host 本机网卡地址 同网段可用 最高
srflx 经 STUN 探知的公网映射地址 跨网直连主力 次之
prflx 探测过程中发现的对称型映射 补充路径 再次
relay TURN 中继分配的地址 兜底,必通 最低

优先级规则体现了一个明确的工程取向:能用直连就不用中继。中继意味着带宽、延迟、金钱三项全付出,是最后的底牌而不是首选。ICE 按「类型优先级乘以本网优先级再加权重」算出每个候选的分数,配对时高分先试。

连通性检查是状态机驱动的三步曲。配对:两端候选交叉组合(本端三种乘对端三种)形成候选对,按优先级排序;探测:从高到低逐对发 STUN 绑定请求,请求本身携带身份校验(短期凭证,密码在协商阶段经 SDP 交换),能收到响应即该对可用;提名:可用的对里挑一个提名为最终通路(常选响应最快的直连对),其余作罢。连接建立后,ICE 定期在通路上发保活包防止 NAT 映射过期——这也是为什么长时间静音的通话不会突然断线。

用一段代码观察全过程:

const pc = new RTCPeerConnection({ iceServers: [ { urls: 'stun:stun.example.net:3478' }, { urls: 'turn:turn.example.net:3478', username: 'user', credential: 'pass' }, ], }); pc.onicecandidate = ({ candidate }) => { if (!candidate) { console.log('收集完毕'); return; } const { type, address, port, priority } = candidate; console.log(type, address + ':' + port, '优先级', priority); // 输出形如: // host 192.168.1.5:54321 优先级 2113937151 // srflx 203.0.113.7:58432 优先级 1677722751 // relay 198.51.100.9:62219 优先级 16777215 };

图:候选来源与打洞配对全景

图:候选来源与打洞配对全景

三、工程实践要点:给候选收集设边界

候选收集有两个工程参数值得主动管理。其一,ICE 候选池:多网卡设备(有 Wi-Fi、有虚拟网卡、有 VPN)可能收集出一大串 host 候选,探测组合暴涨、建立变慢。iceCandidatePoolSize 与地址过滤能控制规模,服务端场景甚至可以直接限定单网卡。其二,收集超时: TURN 不可达时收集会拖很久,监听 icegatheringstatechange 并在超时后强制进入连接阶段(候选可以后到),比无限等待更稳。

⚠️ 常见坑:只看「候选收集到了」不看「候选是什么类型」。日志里只有 host 没有 srflx,说明 STUN 不可达;只有 relay,说明直连探测全败。候选清单是网络环境的第一手体检报告,故障时要先读它。

完整案例:办公室里「同事之间通、跨办公区不通」

背景:某远程协作产品收到反馈:同一办公室内两台设备通话正常,跨办公区必然失败,日志里 iceConnectionState 停在 checking 直到超时。

操作:从失败端导出候选清单,发现只有 host 候选——部署时工程师只配了一个指向内网地址的 STUN 域名,办公网外解析不到。改为公网可达的 STUN 服务后,srflx 候选出现,跨办公区直连成功率升到大多数场景;仍有一批使用运营商级 NAT 的移动端失败,候选清单显示 srflx 与 prflx 探测全败,于是补上 TURN,这类终端全部转为中继通路,连接成功率归一。

结果:三步走完,连接成功率从「同网段可用」提升到全场景可用,中继流量占比约一成多,带宽成本可控。

解读:这个案例是本章逻辑的微缩演练——症状(跨网不通)指向候选清单(缺 srflx),候选清单指向部署缺陷(STUN 不可达),补齐后剩余症状(对称 NAT)指向兜底缺失(无 TURN)。排障顺序永远是从「终端收集到了什么」开始,而不是从「服务器配置了什么」开始。

变式:安全性要求高的企业内网会完全封锁 UDP 出向,此时 srflx 无意义,应直接配置支持 TCP 或 TLS 接入的 TURN(urls 里写 transport 参数),让媒体走 443 端口的 TCP 中继穿过只放行 HTTP 形态流量的防火墙。这属于 4.2 节的部署细节,思路在此先立住:网络封锁什么,就用基础设施补什么。

本节要点回顾

  • ICE 的哲学是穷举验证:不猜唯一地址,收集所有可能身份,两两配对逐一探测。
  • NAT 四型决定打洞成败:锥型之间基本可通,对称对对称是死局,只能中继兜底。
  • 候选优先级体现成本观:host 最高、srflx 次之、relay 最低,能用直连绝不上中继。
  • 连通性检查三步走:配对、探测(带凭证的 STUN 请求)、提名,事后定期保活。
  • 候选清单是体检报告:故障排查从读候选清单开始,类型分布直接指向缺陷环节。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U