# 提名与 ICE 重启 · 拍板与重来

> 控制方怎么「拍板」选定一条路？靠提名——在 STUN 探测里带上 USE-CANDIDATE。而网络剧变、连接彻底断掉时，ICE 还能整个重启重来。这一章讲常规提名 vs 激进提名、ICE 重启换新凭据重新采集，以及持续采集如何支撑移动场景。

- 作者：David（道雾轩）
- 专栏：音视频与 WebRTC 详解（https://daiw.org/manual/webrtc.md）
- 最后更新：2026-07-14
- 原文：https://daiw.org/manual/webrtc/nomination-and-restart
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# 提名与 ICE 重启 · 拍板与重来

[上一章](https://daiw.org/manual/webrtc/ice-controller)说 [controlling 角色](https://daiw.org/manual/webrtc/ice-controller)「拍板」选路。它具体怎么拍板？靠**提名（nomination）**。而当网络发生剧变、选中的路彻底断掉，ICE 还有一招兜底：**整个重启**。这两个机制，一个管「正常怎么定下来」，一个管「出大事怎么重来」。

## 提名：在探测里插一面小旗

[控制方](https://daiw.org/manual/webrtc/ice-controller)选定要用哪条 [`Connection`](https://daiw.org/manual/webrtc/connection-and-checks) 后，怎么告诉对端「就用这条」？它在发给这条连接的 [STUN Binding 请求](https://daiw.org/manual/webrtc/stun-protocol)里，**带上一个 `USE-CANDIDATE` 属性**——相当于插了一面小旗：「这条，钦定了」。受控方收到带旗的探测，就知道这条被提名了。这正是 [`Connection::nominated()`](https://daiw.org/manual/webrtc/connection-and-checks) 标记的东西。

提名有两种风格，`base/connection.h` 的注释就提到「Regular or Aggressive」：

<Callout type="info">
  **常规提名 vs 激进提名——「谋定后动」还是「边打边定」。**

  - **常规提名（Regular）** —— 控制方**先把连通性检查做得差不多**，看清哪条最优，**再**发一轮带 `USE-CANDIDATE` 的探测正式提名它。稳妥，但多一个来回，慢一点。
  - **激进提名（Aggressive）** —— 控制方**在每个探测上都带 `USE-CANDIDATE`**，边检查边提名——第一条通的路立刻就被「提名」用上。快，但可能先用上一条次优的路，之后再切到更好的。

  权衡是**建连速度 vs 选路质量**：激进提名让媒体尽快流动（用户体验好），代价是初期可能不是最优路径，靠[后续的持续选路](https://daiw.org/manual/webrtc/ice-controller)慢慢优化到最好。现代 WebRTC 倾向于「快速可用、再逐步优化」，所以激进提名很常见。一条连接**既 [writable](https://daiw.org/manual/webrtc/connection-and-checks) 又被 nominated**，就成了「选中的连接」，媒体从它走。
</Callout>

## ICE 重启：推倒重来

选定的路不是永久的。手机从 Wi-Fi 走到电梯里断网、网络切换、NAT 映射被回收……选中的连接可能[彻底 `TIMEOUT`](https://daiw.org/manual/webrtc/connection-and-checks)，所有连接都废了。这时需要**ICE 重启（ICE restart）**：

<Callout type="info">
  **ICE 重启 = 换一套全新的 ICE 凭据，把采集和检查从头再来一遍。** 具体地：生成**新的 ice-ufrag / ice-pwd**（[凭据](https://daiw.org/manual/webrtc/sdp-and-jsep)），发起一轮新的 [offer/answer 协商](https://daiw.org/manual/webrtc/offer-answer-handler)带上新凭据；[`P2PTransportChannel`](https://daiw.org/manual/webrtc/p2p-transport-channel) 开一个**全新的 [`PortAllocatorSession`](https://daiw.org/manual/webrtc/port-allocator)** 重新[采集候选](https://daiw.org/manual/webrtc/port-allocator)、重新[配对检查](https://daiw.org/manual/webrtc/connection-and-checks)。新凭据是关键——它让新一轮的 [STUN 探测](https://daiw.org/manual/webrtc/stun-protocol)和旧的区分开，老连接的残留探测不会干扰新会话。

  重启期间，**旧连接若还能用会继续撑着**，直到新连接就绪才切换，尽量不中断通话。这就是为什么你在地铁里视频通话，网络抖一下、卡几秒，却往往能**自己缓过来**——底层正在默默地 ICE 重启，重新为你找一条能通的路。
</Callout>

## 持续采集：为移动而生

还有一个和重启相关的机制：**持续采集（continual gathering）**。默认情况下候选采集完就停了（[gathering complete](https://daiw.org/manual/webrtc/p2p-transport-channel)）；但开启持续采集后，[`PortAllocator`](https://daiw.org/manual/webrtc/port-allocator) 会**一直盯着网络变化**——[新网卡上线](https://daiw.org/manual/webrtc/network-monitoring)（插了网线、连上新 Wi-Fi）就**采集新候选**并 [trickle](https://daiw.org/manual/webrtc/candidates) 给对端，老网卡下线就移除相关候选。这让 ICE 能**不重启就适应网络变化**：多一条新路可用时，[选路](https://daiw.org/manual/webrtc/ice-controller)自然会考虑它、必要时切过去。持续采集 + 动态选路，共同支撑了 WebRTC 的**移动性**——设备网络环境一直在变，通话却能持续。

```mermaid
flowchart TD
    OK["媒体正常流动<br/>(选中连接 writable + nominated)"]
    OK -->|"网络变化:新网卡上线"| CG["持续采集:采新候选 trickle 给对端"]
    CG -->|"更优路径出现"| SW["IceController 无缝切换"]
    SW --> OK
    OK -->|"选中连接彻底 TIMEOUT / 全断"| RS["ICE 重启:新 ufrag/pwd<br/>新 PortAllocatorSession 重采重检"]
    RS -->|"找到新可用路"| OK
```

## 小结与下一章

**提名**是[控制方](https://daiw.org/manual/webrtc/ice-controller)「拍板」的方式：在 [STUN 探测](https://daiw.org/manual/webrtc/stun-protocol)里带 `USE-CANDIDATE`（即 [`nominated()`](https://daiw.org/manual/webrtc/connection-and-checks)）。**常规提名**谋定后动（稳、慢），**激进提名**边打边定（快、可能次优再优化）。**ICE 重启**在连接全断时推倒重来：换新 [ufrag/pwd](https://daiw.org/manual/webrtc/sdp-and-jsep)、开新 [`PortAllocatorSession`](https://daiw.org/manual/webrtc/port-allocator) 重采重检，旧连接撑到新的就绪。**持续采集**盯着网络变化、动态增删候选，和[动态选路](https://daiw.org/manual/webrtc/ice-controller)一起支撑**移动性**——这也是地铁里通话能自己缓过来的原因。

而「网络变化」这件事，谁来感知？是 `rtc_base` 里的 **`NetworkManager`**。它枚举网卡、监测变化，是 ICE 移动性的眼睛。下一章收尾第 2 部分。👉 [网络监测：NetworkManager](https://daiw.org/manual/webrtc/network-monitoring)。

## 参考资料

- [1] libwebrtc 源码.`p2p/base/connection.h`（`nominated`、Regular/Aggressive 注释）、`p2p/base/p2p_transport_channel.cc`（ICE 重启、持续采集）。
- [2] libwebrtc 源码.`p2p/base/port_allocator.h`（`PortAllocatorSession`、continual gathering）。
- [3] IETF RFC 8445「ICE」§ Nominating、ICE Restart;RFC 8838「Trickle ICE」。
