PortAllocator 与候选采集 · 四种 Port
候选由 Port 采集,Port 由 PortAllocator 创建。这一章读 p2p/ 的 PortAllocator/BasicPortAllocator 与 PortAllocatorSession,以及四种 Port——UDPPort、StunPort、TcpPort、TurnPort,它们分别产出哪种候选,以及怎么用 flag 开关它们。
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 路径 | 产出候选 | 干什么 |
|---|---|---|---|
UDPPort | p2p/base/stun_port.h | host(UDP) | 直接用本机网卡的 UDP 地址 |
StunPort | p2p/base/stun_port.h | srflx | 向 STUN 服务器问公网地址 |
TcpPort | p2p/base/tcp_port.h | host(TCP) | 本机网卡的 TCP 地址(UDP 被封时的退路) |
TurnPort | p2p/base/turn_port.h | relay | 向 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(采集流程)。