协议简介
ICE(Interactive Connectivity Establishment,交互式连接建立)是一种 NAT穿透协议,在 WebRTC、VoIP 和视频会议等实时通信场景中被广泛使用。它的主要目标是解决由于 NAT(网络地址转换)和防火墙带来的连接问题,使通信双方能够建立可靠的端到端连接。
广泛用于:
- WebRTC(浏览器实时通信)
- VoIP(语音通话)
- 视频会议系统
- P2P 文件传输系统
其核心思想是:从多个路径中自动发现一条可用路径,并建立连接。
核心目标
- 发现并测试连接路径:通过不同网络路径和地址尝试建立连接。
- NAT穿透:穿越 NAT 和防火墙建立点对点连接。
- 选择最佳连接路径:根据连通性检查的结果选择延迟最低、可用性最好的候选地址对。
- 必要时使用 TURN 进行中继
基本概念
Candidate(候选地址)
ICE 会收集本地、映射和中继地址作为候选:
类型 | 描述 | 优先级 | 是否穿透 |
---|---|---|---|
Host Candidate | 本地地址(如 192.168.x.x) | 高 | 否 |
Server Reflexive Candidate | 使用 STUN 获取的公网映射地址 | 中 | 是 |
Peer Reflexive Candidate | 连通性检查动态发现的对端地址 | 中等偏高 | 是 |
Relay Candidate | TURN 分配的地址,中继传输 | 低 | 是,最稳定 |
STUN(Session Traversal Utilities for NAT)
- 用于查询 NAT 映射后的公网地址,获取 Server Reflexive Candidate。
- 提供最轻量级的 NAT 穿透方式。
TURN(Traversal Using Relays around NAT)
- 当 STUN 穿透失败时,TURN 中继服务器作为数据转发中介。
- 成本高,延迟大,但可靠性高。
ICE Agent
- 每个通信端都运行一个 ICE Agent,它负责候选地址的收集、连通性检查、优先级比较、协商等工作。
工作流程
步骤 1:候选地址收集(Gathering)
每个通信端收集自己的候选地址,包括:
- 本地地址(Host)
- STUN服务器反射地址(Server Reflexive)
- TURN中继地址(Relay)
步骤 2:交换候选地址(Candidate Exchange)
- 使用信令协议(如 SDP,通常通过 SIP、WebRTC 的信令通道)交换候选地址。
步骤 3:连通性检查(Connectivity Checks)
- 使用 STUN 消息对候选地址对(candidate pair)进行测试,看是否能成功通信。
- 成功的连接对会被 ICE 标记为可用。
步骤 4:选择优选连接路径
- 每对候选地址都有优先级(由 ICE 算法计算得出)。
- ICE 会选择具有最高优先级且可达的候选对作为最终连接路径。
步骤 5:建立连接(Nomination)
- 确认并锁定最终使用的候选对。
- 对于双向通信(例如 WebRTC 的数据通道),双方都要确认连接对。
优先级与候选对选择
ICE 候选优先级受以下因素影响:
- 地址类型优先级:Host > Server Reflexive > Relay
- 网络接口类型:有线 > 无线
- 类型偏好(type preference)
- 本地优先级(local preference)
单个候选优先级
priority = (2^24) * type preference +(2^8) * local preference +256 - component ID
- Type Preference:Host > Reflexive > Relay
- Local Preference:用于多网卡排序
- Component ID:RTP/RTCP 区分
候选对优先级(candidate pair)
pair_priority = 2^32 * min(local_priority, remote_priority) + 2 * max(...) + (local > remote ? 1 : 0)
WebRTC 中 ICE 实现
整体架构
WebRTC 使用 ICE 协议结合 STUN 和 TURN,在浏览器内部由 ICE Agent 实现,流程如下:
浏览器 A 信令通道 浏览器 B
────────────► Gather candidates ◄────────────
─────────────► Exchange SDP (包含 candidates) ◄─────────────
──────────────► Connectivity checks (STUN) ◄───────────────
───────────────► Nomination and Selection ◄───────────────
───────────────► 建立数据通道(DTLS + SRTP)◄──────────────
ICE 流程详解(WebRTC 版本)
步骤 1:候选地址收集(ICE Gathering)
浏览器调用 WebRTC API(如 RTCPeerConnection
)时:
- 浏览器会自动:
- 检查本地网络接口,生成 Host 候选地址
- 使用配置的 STUN 服务器获取 Server Reflexive 地址
- 使用配置的 TURN 服务器申请 Relay 候选地址
const pc = new RTCPeerConnection({iceServers: [{ urls: "stun:stun.l.google.com:19302" },{ urls: "turn:your.turn.server", username: "...", credential: "..." }]
});
步骤 2:信令交换(SDP 内部包含候选地址)
通过 createOffer()
生成包含候选的 SDP,交换给对方。
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);// 将 offer.sdp 通过信令(如 WebSocket)发送给对端
对端通过 setRemoteDescription()
接收 SDP 并回传 answer。
步骤 3:候选地址交换(Trickle ICE)
候选地址并不是一次性全部发送,而是逐步收集并发送(trickle ICE):
onicecandidate
事件触发时,每收集到一个 candidate 就发送给对端;- 对端通过
addIceCandidate()
添加该地址。
// 接收远端的 candidate
pc.addIceCandidate(new RTCIceCandidate(remoteCandidate));
步骤 4:连通性检查(STUN 交叉测试)
- 双方根据候选地址对进行连通性检查(connectivity check);
- 使用 STUN Binding Request 消息进行握手;
- 浏览器使用 STUN over UDP/TCP 判断路径可用性;
- 若某对候选可通信,则标记为成功。
步骤 5:候选优选(Nomination)
- 每个候选对被赋予优先级;
- 浏览器选择最优的一对进行“提名”(nomination);
- 一旦确认,浏览器锁定该候选对用于媒体通信。
步骤 6:连接建立并切换至 DTLS/SRTP
ICE 建立连接后,WebRTC 进入安全协商阶段:
- 使用 DTLS(Datagram TLS)建立安全数据通道;
- 使用 SRTP 加密媒体流;
- 数据通道使用 SCTP over DTLS。
候选地址优先级逻辑(WebRTC)
WebRTC 默认优先选择:
- Host(最快,最原始);
- Reflexive(可 NAT 穿透);
- Relay(TURN,中继,最慢但最稳定);
每个候选地址有一个类型优先级(type preference)和本地优先级(local preference)组成:
priority = (2^24) * typePref + (2^8) * localPref + (2^0) * componentId
WebRTC 默认使用此策略排序所有候选对并逐个测试。
ICE 状态机(WebRTC)
可以监听 ICE 状态变化:
pc.oniceconnectionstatechange = () => {console.log('ICE 状态:', pc.iceConnectionState);
};
状态可能值包括:
new
:未开始checking
:进行连通性检查connected
:至少有一个连接建立completed
:所有连接建立完毕(非 Trickle)disconnected
:网络临时中断failed
:连接失败closed
:连接已关闭
总结
步骤 | 关键点 |
---|---|
候选地址收集 | Host、STUN(Reflexive)、TURN(Relay) |
候选交换 | 通过 SDP + trickle ICE |
连通性检查 | STUN 探测路径可用性 |
优选与提名 | 基于优先级选最优地址对 |
连接建立 | 最终选中路径,建立 DTLS/SRTP |
相关协议标准
协议 | 说明 |
---|---|
RFC 8445 | ICE 规范(最新) |
RFC 5245 | 旧版 ICE 标准 |
RFC 5389 | STUN 协议标准 |
RFC 5766 | TURN 协议标准 |
RFC 7589 | TURN over TCP |
优缺点
优点 | 缺点 |
---|---|
适应多种网络环境,穿透强 | 实现复杂,调试难 |
自动化建立连接,提升体验 | TURN 中继性能和成本问题 |
标准成熟,兼容性好 | STUN、TURN 可用性影响大 |