文章目錄
- 前言
- WebRTC 的 ICE candidate 協商
- 1. 什么是 ICE candidate?
- 2. ICE 協商的流程
- 3.前端使用 ICE candidate 協商代碼示例
- 1)收集 candidate 并發送
- 2)WebSocket 接收 candidate 并添加
- 4. ICE candidate 的類型
- 5. ICE 協商常見問題
- 6. 關鍵調試點
- 7. 代碼片段加日志示例
- 總結
前言
WebRTC 的 ICE candidate 協商
WebRTC 的 ICE candidate 協商
1. 什么是 ICE candidate?
- ICE(Interactive Connectivity Establishment) 是 WebRTC 用于 NAT 穿透、建立點對點連接的核心協議。
- candidate(候選地址)是指本地網絡環境下所有可能的可用地址(如本地IP、公網IP、中繼服務器IP等)。
- 通過收集和交換 candidate,WebRTC 能找到一條可用的網絡路徑,實現端到端音視頻傳輸。
2. ICE 協商的流程
- 雙方創建 RTCPeerConnection,并設置 ICE 服務器(通常是 STUN/TURN)。
- 本地收集 candidate:瀏覽器會自動收集本地所有可用的網絡地址(candidate)。
- onicecandidate 事件觸發:每收集到一個 candidate,就通過信令服務器發送給對端。
- 對端收到 candidate,通過
addIceCandidate
添加到自己的 RTCPeerConnection。 - 雙方不斷交換 candidate,直到找到一條可用的網絡路徑,ICE 連接建立,媒體流就能傳輸了。
3.前端使用 ICE candidate 協商代碼示例
1)收集 candidate 并發送
const pc = new RTCPeerConnection({iceServers: [// 免費的公共 STUN 服務,適用于測試和輕量級應用{ urls: "stun:stun.l.google.com:19302" },],})
pc.onicecandidate = (e) => {if (e.candidate) {ws.send(JSON.stringify({ type: "candidate", candidate: e.candidate }))}
}
-
每當本地收集到一個 candidate,就通過 WebSocket 發送給對方。
RTCPeerConnection ,截圖自MDN。
2)WebSocket 接收 candidate 并添加
前端可以用 ws 這個庫。
ws.onmessage = async (msg) => {if (data.type === "candidate") {try {await pc.addIceCandidate(data.candidate)} catch (e) {}}}
- 收到對方的 candidate 后,調用
addIceCandidate
添加到本地 RTCPeerConnection。
4. ICE candidate 的類型
- host:本地局域網 IP 地址
- srflx:服務器反射地址(通過 STUN 服務器獲取的公網 IP)
- relay:中繼地址(通過 TURN 服務器獲取,適合復雜 NAT/防火墻環境)
5. ICE 協商常見問題
- 沒有 candidate 交換:雙方無法建立連接,媒體流無法傳輸。
- addIceCandidate 報錯:SDP 協商順序不對,或 candidate 格式有誤。
- NAT/防火墻阻斷:需要配置 TURN 服務器。
- 局域網可通,公網不通:STUN 只能穿透部分 NAT,復雜網絡需 TURN。
6. 關鍵調試點
- 在
onicecandidate
、addIceCandidate
前后加日志,確認 candidate 是否收發完整。 - 檢查 candidate 的類型和內容,確認是否有
srflx
或relay
類型。 - 瀏覽器控制臺查看 ICE 相關報錯(如 ICE failed、addIceCandidate failed 等)。
7. 代碼片段加日志示例
pc.onicecandidate = (e) => {if (e.candidate) {console.log('Send ICE candidate:', e.candidate);ws.send(JSON.stringify({ type: "candidate", candidate: e.candidate }))}
}else if (data.type === "candidate") {console.log('Receive ICE candidate:', data.candidate);try {await pc.addIceCandidate(data.candidate)} catch (e) {console.error('addIceCandidate error', e);}
}
總結
- ICE candidate 協商是 WebRTC 能否連通的關鍵,決定了媒體流能否端到端傳輸。