PortAllocator 与候选采集 · 四种 Port

候选由 Port 采集,Port 由 PortAllocator 创建。这一章读 p2p/ 的 PortAllocator/BasicPortAllocator 与 PortAllocatorSession,以及四种 Port——UDPPort、StunPort、TcpPort、TurnPort,它们分别产出哪种候选,以及怎么用 flag 开关它们。

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

PortAllocator 与候选采集 · 四种 Port

候选不会凭空出现,得有人去「采集」。采集的执行者是 Port,而创建和调度 Port 的是 PortAllocator。这一章读这套采集机制——它是 ICE 第一步的引擎。

PortAllocator:采集的总调度

P2PTransportChannel 不亲自采集候选,而是委托给 PortAllocator(p2p/base/port_allocator.h,默认实现 BasicPortAllocator,在 p2p/client/)。当 MaybeStartGathering 被 SetLocalDescription 触发时,流程是(g3doc/ice.md):

MaybeStartGathering()
  → PortAllocator 创建一个 PortAllocatorSession(一次采集会话)
     → Session 按配置创建各种 Port
        → 每个 Port 开始采集它那一类候选
           → 采到就通过 SignalCandidateGathered 报上去
  • PortAllocatorSession(p2p/base/port_allocator.h)—— 一次采集会话。ICE 重启时会开一个新 session 重新采集,老的作废。用「会话」把一轮采集封装起来,便于整体管理和替换。
  • 采集是异步、持续的:候选一个个冒出来(host 最快、srflx 要等 STUN 往返、relay 要等 TURN 分配),trickle 给应用。

四种 Port,四种候选

Port 是「一种本地通信机制」的抽象(g3doc/ice.md)。它有一个基类 Port(p2p/base/port.h)和四个实现,每种产出一类候选:

Port 实现canonical 路径产出候选干什么
UDPPortp2p/base/stun_port.hhost(UDP)直接用本机网卡的 UDP 地址
StunPortp2p/base/stun_port.hsrflx向 STUN 服务器问公网地址
TcpPortp2p/base/tcp_port.hhost(TCP)本机网卡的 TCP 地址(UDP 被封时的退路)
TurnPortp2p/base/turn_port.hrelay向 TURN 服务器申请中继地址

(注意 UDPPort 和 StunPort 都定义在 stun_port.h 里——UDPPort 是基础,StunPort 在它之上加了向 STUN 服务器查询的能力。)它们共享 Port 基类的大量逻辑(管理候选、创建 Connection、收发包)。

一台设备通常有多个网络接口(Wi-Fi、有线、蜂窝),PortAllocator 会为每个接口、每种类型都建 Port。 于是一次采集可能产出十几个候选:每个网卡一个 host(UDP)、一个 host(TCP)、一个 srflx(经 STUN)、可能还有 relay(经 TURN)。候选越多,配对越多,找到能通路径的机会越大——这正是 ICE「全备齐」哲学的落地。当然候选太多也会让连通性检查变多,所以有各种策略(如按接口/网络成本裁剪)来平衡。

用 flag 开关采集

采集行为可以通过 PortAllocator 的一组 flag 精细控制(p2p/base/port_allocator.h)。几个真实的:

// p2p/base/port_allocator.h(节选 flag)
PORTALLOCATOR_DISABLE_UDP        = 0x01,   // 禁用 UDP host 候选
PORTALLOCATOR_DISABLE_TCP        = 0x08,   // 禁用 TCP host 候选
PORTALLOCATOR_ENABLE_IPV6        = 0x40,   // 启用 IPv6 候选
PORTALLOCATOR_DISABLE_UDP_RELAY  = 0x1000, // 禁用 UDP 中继

这些 flag 让上层能按需裁剪:比如某些企业环境禁 UDP,就只能靠 TCP host / TURN-TCP;要支持 IPv6 就开 ENABLE_IPV6。采集哪些候选,是可配置的策略——又是 WebRTC 可定制哲学的体现。IceServers(STUN/TURN 服务器地址)则通过连接级的 RTCConfiguration 传入,决定 StunPort / TurnPort 去问哪台服务器。

一张采集图

图表加载中…

小结与下一章

候选采集:P2PTransportChannel 委托 PortAllocator(BasicPortAllocator)创建 PortAllocatorSession(一次采集会话,ICE 重启换新的),session 按配置建四种 Port——UDPPort(host/UDP)、StunPort(srflx)、TcpPort(host/TCP)、TurnPort(relay),每种产一类候选,异步 trickle 上报。多网卡 × 多类型 → 候选众多,提高穿透率;用 flag 精细开关。

StunPort 靠 STUN 问出公网地址,而 STUN 还是连通性检查的核心。下一章专讲这个 ICE 的「万能工具」协议。👉 STUN 协议。

参考资料

  • [1] libwebrtc 源码.p2p/base/port_allocator.h、p2p/client/basic_port_allocator.h(采集调度与 flag)。
  • [2] libwebrtc 源码.p2p/base/port.h、stun_port.h、tcp_port.h、turn_port.h(四种 Port)。
  • [3] libwebrtc 源码.g3doc/ice.md(采集流程)。

本页目录