原文鏈接:
https://mp.weixin.qq.com/s?__biz=MzIzMjY3MjYyOA==&mid=2247498075&idx=2&sn=6021a2f60b1e7c71ce4d7af6df0b9b89&chksm=e893e540dfe46c56323322e780d41aec1f851925cfce8b76b3f4d5cfddaa9c7cbb03a7ae4c25&scene=178&cur_album_id=3146991347015499781#rd
一、WebRTC ICE
1.1 ICE 是什么?
在 WebRTC(網頁實時通信)技術體系中,ICE(Interactive Connectivity Establishment,交互式連接建立) 是解決 “設備間如何突破網絡壁壘(如 NAT 網關)建立直接通信” 的核心協議。它通過整合 STUN(會話穿越實用工具) 和 TURN(中繼穿越實用工具),動態收集通信候選地址、檢查連通性,并最終選擇最優路徑(優先 P2P,失敗時降級為中繼),確保實時音視頻、數據傳輸的可靠性
1.2 為什么需要 ICE?
WebRTC 的目標是實現 “瀏覽器 / 終端設備間的直接通信(P2P)”,但現實網絡中存在兩大障礙:
- IP 地址短缺:IPv4 地址耗盡導致絕大多數設備處于局域網內,僅擁有內網 IP(如 192.168.x.x、10.x.x.x),無法直接被公網設備訪問。
- NAT 網關隔離:NAT(網絡地址轉換)是解決 IP 短缺的核心技術,但它會 “隱藏” 內網設備的真實地址,僅允許內網設備主動發起的外網連接,拒絕外部設備的主動訪問 —— 這直接阻斷了 P2P 通信的可能性。
ICE 的核心思想正是繞開 NAT 限制:通過收集設備的 “通信候選地址(Candidate)”,嘗試不同路徑的連通性,最終找到一條能讓兩端互通的路徑。
1.3 通信候選地址(Candidate)
ICE 為每個設備(稱為 “代理”)收集多種 Candidate 地址(IP + 端口 + 傳輸協議的組合,WebRTC 中默認用 UDP),每種 Candidate 對應一種潛在的通信路徑。核心類型如下:
Candidate 類型 | 來源與作用 | 適用場景 |
---|---|---|
Host Candidate(本地候選) | 設備本地網卡的真實地址(如內網 IP 或公網 IP) | 兩端處于同一局域網(如辦公室內設備),或一端擁有公網 IP |
Srflx Candidate(服務器反射候選) | 設備向 STUN 服務器發送請求,STUN 返回 NAT 網關的 “公網映射地址”(內網 IP 經 NAT 轉換后的公網地址) | 兩端均通過 圓錐型 NAT 接入公網,可通過反射地址實現 P2P 打洞 |
Prflx Candidate(對等反射候選) | 連通性檢查過程中,通過對端的 STUN Binding 請求 “動態發現” 的 NAT 反射地址 | 補充 Srflx 覆蓋不到的場景(如對稱型 NAT 下的臨時映射地址) |
Relay Candidate(中繼候選) | 設備向 TURN 服務器請求,由 TURN 分配的 “中繼地址”(所有數據通過 TURN 服務器轉發) | P2P 打洞失敗時(如對稱型 NAT 間通信),降級為中繼傳輸 |
關鍵區分:Srflx 與 Prflx |
- Srflx 是通過 STUN 服務器主動獲取的,提前通過信令交換給對端;
- Prflx 是在 連通性檢查階段動態發現的,無需提前交換,僅在檢查過程中生成。
1.4 STUN 與 TURN 協議
ICE 本身不直接 “穿越 NAT”,而是依賴 STUN 和 TURN 實現核心能力。二者分工明確:STUN 負責 “發現 NAT 映射地址” 和 “檢查連通性”,TURN 負責 “P2P 失敗時提供中繼”。
STUN:NAT 地址發現與連通性檢查
STUN(Session Traversal Utilities for NAT)是一種輕量級協議,主要解決兩個問題:
- 獲取 NAT 公網映射地址:內網設備向 STUN 服務器發送
Binding Request
,STUN 服務器返回設備的 “公網映射地址(MAPPED-ADDRESS)”,設備據此生成 Srflx Candidate。 - 驗證連通性:ICE 用 STUN 的
Binding Request/Response
檢查 “候選地址對(Candidate Pair)” 是否能互通(即 “打洞” 是否成功)。
(1)STUN 的版本演進:RFC3489 vs RFC5389
ICE 僅支持 RFC5389(現代 STUN),因為早期的 RFC3489(Classic STUN)存在諸多局限性:
特性 | RFC3489(Classic STUN) | RFC5389(現代 STUN) |
---|---|---|
傳輸協議支持 | 僅 UDP | 支持 UDP/TCP/TLS |
安全認證 | 無 | 支持短期 / 長期憑證認證 |
NAT 類型覆蓋 | 不支持對稱型 NAT | 支持對稱型 NAT 檢測 |
IPv6 支持 | 無 | 支持 IPv6 |
地址篡改防護 | 無 | 提供 XOR-MAPPED-ADDRESS |
(2)STUN 消息格式:20 字節頭 + 可變屬性
STUN 消息由 “固定頭部” 和 “可變屬性” 組成,結構如下:
-
關鍵頭部字段:
- 魔術字(Magic Cookie):固定值
0x2112A442
,用于區分 STUN 消息與其他協議(如 RTP),并參與 XOR 地址計算。 - 事務 ID(Transaction ID):96 位隨機值,用于關聯 “請求(Request)” 與 “響應(Response)”(避免多請求時混淆)。
- 魔術字(Magic Cookie):固定值
ICE 核心擴展屬性(STUN 為 ICE 新增的關鍵屬性):
屬性名 | 作用 |
---|---|
PRIORITY | 標識 Candidate 的優先級,用于計算 Candidate Pair 的優先級(決定檢查順序) |
USE-CANDIDATE | 提名 Candidate Pair 為 “可用路徑”,觸發后續 DTLS 加密連接建立 |
ICE-CONTROLLING | 標識當前設備為 “控制角色(Controlling)”,攜帶 Tie-breaker 解決角色沖突 |
ICE-CONTROLLED | 標識當前設備為 “被控角色(Controlled)”,攜帶 Tie-breaker 解決角色沖突 |
XOR-MAPPED-ADDRESS | 對映射地址進行 XOR 加密,防止 NAT 網關篡改地址(修復 ALG 設備的兼容性) |
MESSAGE-INTEGRITY | 基于 HMAC-SHA1 的消息完整性校驗(用 ICE 協商的 ice-pwd 計算) |
FINGERPRINT | CRC32 指紋校驗,進一步區分 STUN 消息與其他協議(如 RTP/RTCP) |
TURN:P2P 失敗時的中繼方案
當 STUN 無法打通 NAT(如兩端均為對稱型 NAT)時,ICE 會降級為 TURN(Traversal Using Relays around NAT) 中繼傳輸。TURN 本質是一個 “中繼服務器”,核心作用是:
- 為設備分配 Relay Candidate(中繼地址);
- 轉發兩端的音視頻數據(所有流量經 TURN 服務器中轉)。
TURN 的關鍵特性:
- 協議兼容性:基于 STUN 擴展(除
ChannelData
消息外,其他消息格式與 STUN 一致),支持 UDP/TCP/TLS; - 權限控制:設備需先向 TURN 服務器發送
Allocate
請求 “申請中繼資源”,并創建 Permission(許可)—— 僅允許被許可的對端地址通過 TURN 轉發數據; - 效率優化:支持
ChannelData
消息(無 STUN 頭部,減少開銷),適合大流量傳輸。
1.5 ICE 細節
NAT 類型
NAT 網關的轉發規則直接決定 P2P 能否成功,ICE 需先檢測 NAT 類型,再選擇合適的 Candidate。常見 NAT 類型分為 圓錐型 NAT 和 對稱型 NAT,其中圓錐型又細分為三類:
NAT 類型 | 核心規則 | P2P 兼容性 |
---|---|---|
完全圓錐型 NAT | 內網 IP:Port 映射為固定公網 IP:Port,任何外網設備可向該公網地址發送數據 | 最佳(支持所有 P2P 場景) |
IP 限制圓錐型 NAT | 內網 IP:Port 僅向 “主動訪問過的外網 IP” 開放(端口不限) | 較好(僅限制 IP,支持大部分場景) |
Port 限制圓錐型 NAT | 內網 IP:Port 僅向 “主動訪問過的外網 IP:Port” 開放(IP + 端口雙重限制) | 一般(需精準匹配端口) |
對稱型 NAT | 內網 IP:Port 向不同外網 IP:Port 發起請求時,映射不同的公網 IP:Port | 最差(P2P 幾乎無法打通,需 TURN 中繼) |
NAT 類型檢測流程:
ICE 代理通過向 STUN 服務器發送多輪請求,按以下順序判斷 NAT 類型:
- 檢查防火墻是否阻斷所有 UDP 包(若無法收到 STUN 響應,判定為 “UDP 阻斷”);
- 檢查設備是否擁有公網 IP(若本地 IP 與 STUN 返回的映射地址一致,判定為 “公網設備”);
- 檢測是否為 “完全圓錐型 NAT”(向不同 STUN 服務器發送請求,若映射地址不變,且外部可主動訪問);
- 檢測是否為 “對稱型 NAT”(向同一 STUN 服務器的不同端口發送請求,若映射地址變化,判定為對稱型);
- 區分 “IP 限制” 與 “Port 限制圓錐型”(向同一 IP 的不同端口發送請求,若能收到響應則為 IP 限制,否則為 Port 限制)。
具體能否打通可以看下表:
ICE協議包括stun和turn協議,turn協議是stun協議的補充,可以簡單粗暴理解為如果stun不通,那就走turn,turn可以理解為一個中繼代理轉發。
ICE 的角色與模式
ICE 定義了 “角色” 和 “模式”,用于規范兩端的行為邏輯,避免沖突。
(1)ICE 角色:Controlling vs Controlled
ICE 兩端分為兩種角色,決定 “誰負責提名可用路徑”:
- Controlling(控制角色):主動提名 “可用的 Candidate Pair”,由 Offer 方(主動發起會話的設備)擔任;
- Controlled(被控角色):被動接受 Controlling 提名的路徑,由 Answer 方(被動響應會話的設備)擔任。
角色沖突解決:
若兩端均誤判為 Controlling(或 Controlled),通過 Tie-breaker(隨機值) 解決:
- 沖突時,兩端在 STUN Binding 請求中攜帶
ICE-CONTROLLING
/ICE-CONTROLLED
屬性及 Tie-breaker 值; - 比較 Tie-breaker 大小:值更大的一端為 Controlling,另一端需切換為 Controlled;
- 若某端需切換角色,對端會返回
487(Role Conflict)
錯誤,觸發角色變更。
ICE 模式:Full ICE vs Lite ICE
ICE 代理分為兩種模式,對應不同的部署場景:
模式 | 核心行為 | 適用場景 |
---|---|---|
Full ICE | 主動收集所有 Candidate,主動發起連通性檢查,支持角色切換 | 客戶端設備(如瀏覽器、APP) |
Lite ICE | 僅被動響應連通性檢查(不主動發起),角色固定為 Controlled,SDP 含 a=ice-lite | 公網服務器(如媒體服務器、CDN 節點) |
注意:Full ICE 與 Lite ICE 互通時,僅 Full ICE 端主動發起檢查,Lite 端僅需回應即可。
ICE 的完整工作流程
ICE 從 “收集 Candidate” 到 “建立通信” 分為 8 個核心步驟,流程如下:
步驟 1:收集 Candidate(Candidate Collection)
ICE 代理從本地、STUN、TURN 收集所有可能的 Candidate,并去重(若兩個 Candidate 的地址和 Base 地址相同,則刪除重復項):
- Host Candidate:遍歷本地網卡(物理 / 虛擬),獲取所有內網 / 公網 IP:Port;
- Srflx Candidate:向 STUN 服務器發送
Binding Request
,獲取 NAT 公網映射地址; - Relay Candidate:向 TURN 服務器發送
Allocate
請求,獲取中繼地址; - Foundation 生成:為每個 Candidate 生成唯一標識(基于類型、IP、協議計算),用于后續去重。
步驟 2:交換 Candidate(Candidate Exchange)
兩端通過 信令服務器 交換 Candidate(需與 SDP 協商同步),有兩種交換方式:
- 傳統方式:收集完所有 Candidate 后,將其嵌入 SDP 中一次性發送;
- Trickle ICE(涓流 ICE):SDP 與 Candidate 分開發送(SDP 先發送,Candidate 收集一個發一個),SDP 需包含
a=ice-options:trickle
。
優勢:Trickle ICE 可縮短連接建立時間(無需等待所有 Candidate 收集完成),是 WebRTC 的默認方式。
SDP 中 Candidate 的格式示例:
a=candidate:240568271 1 udp 1686052607 174.139.8.82 64462 typ srflx raddr 10.1.1.19 rport 64462 generation 0 ufrag TWCy network-id 2
字段含義解析:
字段 | 含義 |
---|---|
240568271 | Foundation(Candidate 唯一標識) |
1 | Component ID(媒體類型:1=RTP,2=RTCP;WebRTC 默認用 RTCP-mux 合并為 1) |
udp | 傳輸協議(UDP/TCP) |
1686052607 | Priority(Candidate 優先級,數值越大優先級越高) |
174.139.8.82 | Candidate 地址(公網映射地址,對應 Srflx 類型) |
64462 | 端口號 |
typ srflx | Candidate 類型(host/srflx/prflx/relay) |
raddr 10.1.1.19 | Base 地址(Srflx 的本地內網地址) |
ufrag TWCy | ICE 用戶名片段(用于 STUN 認證,與對端 ufrag 組合為 USERNAME) |
步驟 3:生成 Candidate Pair(候選地址對)
兩端收到對方的 Candidate 后,按以下規則組合為 Candidate Pair(本端 Candidate + 遠端 Candidate):
- 匹配條件:
Component ID 相同
(如均為 RTP 的 1)且傳輸協議相同
(如均為 UDP); - 地址修整:若 Candidate 為 Srflx,需用其 Base 地址(本地內網地址)替換,確保檢查邏輯正確。
步驟 4:連通性檢查(Connectivity Checks)
ICE 按 Candidate Pair 的優先級 排序(優先級高的先檢查),通過 STUN Binding Request/Response 驗證 “該地址對是否能互通”。
(1)Candidate Pair 優先級計算
優先級決定檢查順序,公式如下(核心邏輯:優先選擇 “本地優先” 且 “對端優先” 的組合):
Pair Priority = 2^32 * MIN(G, D) + 2 * MAX(G, D) + (G > D ? 1 : 0)
G
:Controlling 角色的 Candidate 優先級;D
:Controlled 角色的 Candidate 優先級;MIN(G,D)
/MAX(G,D)
:取兩者的最小值和最大值,確保 “高優先級 Candidate 優先匹配”。
(2)檢查方式
- Ordinary Checks(普通檢查):Controlling 端按優先級順序,主動向 Controlled 端發送 STUN Binding Request;
- Triggered Checks(觸發式檢查):Controlled 端收到檢查請求后,立即向 Controlling 端發起反向檢查(提高效率,避免等待)。
(3)檢查成功的條件
- 收到對端的 STUN Binding Success Response;
- 地址對稱:請求的 “源地址 = 響應的目的地址” 且 “請求的目的地址 = 響應的源地址”(排除 NAT 地址映射不對稱的情況)。
(4)重傳機制
若未收到響應,ICE 按 指數退避策略 重傳(初始間隔 50ms,每次翻倍,直至最大重傳次數或超時)。
步驟 5:生成 Valid List(有效地址列表)
將 “連通性檢查成功” 的 Candidate Pair 按優先級排序,組成 Valid List(可用路徑列表)。
步驟 6:提名 Candidate Pair(Nomination)
由 Controlling 角色 從 Valid List 中選擇 “最優路徑” 并提名,分為兩種提名方式:
- 普通提名(Regular Nomination):分兩步檢查
- 第一次檢查:不帶
USE-CANDIDATE
屬性,僅驗證連通性; - 第二次檢查:對 Valid List 中的 Pair 發送帶
USE-CANDIDATE
的請求,確認提名。
- 第一次檢查:不帶
- 進取型提名(Aggressive Nomination):一步完成
- 所有檢查請求均帶
USE-CANDIDATE
屬性; - 第一個檢查成功的 Pair 直接被提名(效率更高,WebRTC 默認采用)。
- 所有檢查請求均帶
步驟 7:建立加密連接(DTLS)
提名完成后,兩端基于 “選中的 Candidate Pair” 建立 DTLS(數據報傳輸層安全)連接——WebRTC 要求所有數據(音視頻、DataChannel)必須加密,DTLS 負責證書交換、密鑰協商,確保傳輸安全。
步驟 8:連接保活(Keep-Alive)
NAT 網關會 “超時清理” 長期無數據的連接(默認超時時間 30s~5min),ICE 通過以下方式保活:
- 定期發送 STUN Binding Request/Indication(初始間隔 50ms,穩定后間隔 2.5s);
- 若未收到響應,觸發重傳或重新選擇 Valid List 中的備用路徑。
ICE 的狀態流轉
ICE 代理在工作過程中會經歷以下狀態,用于標識連接進展:
狀態 | 含義 |
---|---|
Waiting | 未開始連通性檢查,等待 Candidate 收集或交換完成 |
In-Progress | 連通性檢查已啟動,但尚未有成功的 Pair |
Succeeded | 已找到可用的 Candidate Pair,DTLS 連接建立完成,可開始數據傳輸 |
Failed | 所有 Candidate Pair 檢查失敗,且 TURN 中繼不可用(連接徹底失敗) |
Frozen | Candidate Pair 暫不檢查(如等待其他 Pair 檢查結果,后續可解凍) |
二、WebRTC ICE的意義
2.1 價值
- 解決 NAT 穿越難題:通過多 Candidate 類型和動態檢查,覆蓋 90% 以上的網絡場景;
- 優先 P2P 通信:減少對中繼服務器的依賴,降低延遲(P2P 延遲通常 <100ms,中繼延遲可能> 200ms);
- 可靠性保障:Valid List 提供備用路徑,某條路徑中斷時可快速切換到其他路徑。
2.2 局限性
- 依賴信令服務器:ICE 需信令服務器交換 SDP 和 Candidate,無法獨立工作;
- 對稱型 NAT 需中繼:對稱型 NAT 下 P2P 無法打通,需依賴 TURN 服務器(增加帶寬成本和延遲);
- 防火墻限制:部分嚴格防火墻會阻斷 UDP 端口,需降級為 TCP/TLS(效率較低)。
2.3 總結
ICE 是 WebRTC 實現 “實時 P2P 通信” 的核心支柱,它通過 “收集候選地址→檢查連通性→提名最優路徑” 的閉環流程,繞開了 NAT 網關的限制,同時整合 STUN 和 TURN 實現 “P2P 優先、中繼兜底” 的通信策略。理解 ICE 的工作原理,是排查 WebRTC 連接失敗(如 “無法建立 P2P 連接”“延遲過高”)的關鍵 —— 例如,連接失敗可能是 STUN/TURN 服務器不可用、NAT 類型為對稱型且無中繼資源,或 Candidate 交換不完整。