候选 · host / srflx / prflx / relay

ICE 的第一步是收集候选——每一个「我可能被联系到的地址」。这一章读 api/candidate.h 的 IceCandidateType,讲清四种候选:主机候选、服务器反射候选、对端反射候选、中继候选,它们各自怎么来、优先级如何,以及为什么要同时准备这么多条备选。

作者 David更新于 第 17 篇(共 112 篇)

候选 · host / srflx / prflx / relay

ICE 四步的第一步是「收集候选」。候选(candidate) 就是一个「我可能被对端联系到的传输地址」——一个 IP、端口、协议的组合。ICE 的哲学是广撒网,所以每一端都会尽可能多地收集候选。这一章讲清候选的四种类型,它们是理解 ICE 的基础词汇。

四种类型

api/candidate.h 里的 IceCandidateType 枚举,干净利落地给出四种:

// api/candidate.h
enum class IceCandidateType : int { kHost, kSrflx, kPrflx, kRelay };

它们对应四种「怎么得到这个地址」的方式,从「最直接」到「最兜底」:

四种候选,四种「找到我」的路径:

  • kHost(主机候选) —— 设备本机网卡的地址(如 192.168.1.5:50000)。最直接:如果两端在同一局域网,用它就能直连,零绕路。但跨 NAT 时它对外没用。
  • kSrflx(服务器反射候选,server-reflexive) —— 设备经 STUN 服务器问出的公网地址。设备向 STUN 服务器发个包,服务器回答「我看到你来自 203.0.113.7:60000」——这个「NAT 外面看到的地址」就是 srflx 候选。这是穿越 NAT 的主力。
  • kPrflx(对端反射候选,peer-reflexive) —— 在连通性检查过程中意外发现的地址。有时对端探测包来自一个双方都没预料到的地址(某些 NAT 行为),这个新地址就地成为一个 prflx 候选。它是「检查中冒出来的惊喜」。
  • kRelay(中继候选,relay) —— TURN 中继服务器分配的地址。当直连怎么都不通(对称 NAT、严格防火墙),就让媒体经 TURN 服务器转发。它最兜底、也最费(绕一道服务器、增延迟、耗服务器带宽),但保证能通——只要两端都连得上 TURN。

本地候选 vs 远端候选

候选分两个来源(g3doc/ice.md):

注意:候选的交换不必等 SDP 全部完成。现代 WebRTC 用 Trickle ICE——候选一边采集、一边陆续通过信令发给对端(而非等全部采完再一起发),这样连通性检查能更早开始,建连更快。你在 PeerConnectionObserver 里反复收到的 OnIceCandidate 回调,就是候选在「trickle」。

优先级:先试快的

一端往往有好几个候选,先试哪个?ICE 给每个候选算一个优先级,配成 Connection 后按优先级高低排序检查。大致的偏好顺序:

host(最快,同网直连)  >  srflx(穿 NAT 直连)  >  relay(中继,最慢但保底)

Candidate(api/candidate.h)结构里带着 type()、地址、协议(UDP/TCP)、priority()、以及一个 foundation(用于把「同类同源」的候选归组)。优先级的计算综合了类型、网络接口、协议等因素——目标是让延迟低、代价小的路先被选中,中继只在别无选择时才上。

为什么要准备这么多

初学者常问:既然 host 通不了就用 srflx、srflx 不行再用 relay,为什么不按顺序试,非要一次全备齐?

因为你事先不知道哪条能通——NAT 的行为千奇百怪。 有的 NAT 让 srflx 直连轻松成功,有的(对称 NAT)会让 srflx 也失败、只能走 relay;两端 NAT 类型的组合更是难以预测。ICE 的智慧就在于不预测、全备齐、并行试:同时收集 host / srflx / relay,同时对所有配对做连通性检查,让「哪条能通、哪条最快」在实测中自然分出胜负。这比「猜一条、失败再换」快得多、也可靠得多。代价是要维护一堆候选和连接,但换来的是高穿透率和低建连延迟——非常值。

小结与下一章

候选是「我可能被联系到的地址」,四种(IceCandidateType):kHost(本机网卡,同网直连)、kSrflx(STUN 问出的公网地址,穿 NAT 主力)、kPrflx(检查中意外发现)、kRelay(TURN 中继,最兜底保底)。候选分本地 / 远端,用 Trickle ICE 边采边发(OnIceCandidate 回调)。每个候选有优先级(host > srflx > relay),让快的先试。ICE 全备齐、并行试,不靠预测靠实测。

候选从哪来?靠 Port 去采集,而 Port 由 PortAllocator 创建。下一章看这套采集机制,以及四种 Port 分别产哪种候选。👉 PortAllocator 与候选采集。

参考资料

  • [1] libwebrtc 源码.api/candidate.h(IceCandidateType、Candidate 结构)。
  • [2] libwebrtc 源码.g3doc/ice.md(候选类型与本地 / 远端来源)。
  • [3] IETF RFC 8445「ICE」§ Candidates;RFC 8838「Trickle ICE」。

本页目录