【网络通信 -- WebRTC】WebRTC 基础知识 -- ICE 交互总结
ICE 角色
offer (主动发起)的一方为 controlling 角色
answer (被动接受)的一方为 controlled 角色
full ice agent 必须是 controlling role,lite ice agent 是 controlled;srs 仅支持 lite ice
ICE 模式
FULL ICE,双方都要进行连通性检查;ice 客户端实现,该模式既可以收 binding request,也可以发 binding request
Lite ICE,在 FULL ICE 和 Lite ICE 互通时,只需要 FULL ICE 一方进行连通性检查,Lite 一方只需回应 response 消息,该模式对于部署在公网的设备比较常用;只接受并回复 binding request 请求,不会主动发送 binding request 请求给对方
sdp 中有 a=ice-lite 字样
srs 服务器采用 lite-ice 模式
Candidate 地址
媒体传输的候选地址,组成 candidate pair 做连通性检查,确定传输路径
Type 类型
Host (Host Candidate),该地址是一个真实的主机,参数中的地址和端口对应一个真实的主机地址,该地址来源于本地的物理网卡或逻辑网卡上的地址,对于具有公网地址或者同一内网的端可以用;
Srvflx (Server Reflexive Candidate),该地址是通过 Cone NAT (锥形 NAT) 反射的类型,参数中的地址和端口是端发送 Binding 请求到 STUN/TURN server 经过 NAT 时,NAT 上面分配的地址和端口
Relay (Relayed Candidate),该地址是端发送 Allocate 请求到 TURN server,由 TURN server 用于中继的地址和端口,该地址和端口是 TURN 服务用于在两个对等点之间转发数据的地址和端口,是一个中继地址端口;( 可能是本机或 NAT 地址);
Prflx(Peer Reflexive Candidate),该地址是通过发送 STUN Binding 时,通过 Binding 获取到的地址;在建立连接检查期间新发生,参数中的地址和端口是端发送 Binding 请求到 STUN/TURN server 经过 NAT 时,NAT 上分配的地址和端口
Componet ID
传输媒体的类型,1 代表 RTP; 2 代表 RTCP
WebRTC 采用 Rtcp-mux 方式,也就是 RTP 和 RTCP 在同一通道内传输,减少 ICE 的协商和通道的保护
Priority
Candidate 的优先级
Base
candidate 的基础地址
SDP 中的 Candidate 地址描述
ICE 保活
对于每个 ICE 通道,都需要为其会话进行保护
采用 STUN binding request 或者 STUN binding indication
如果没有收到响应,则会重传,直到最大重传次数
ICE 角色冲突的解决方法
当两端角色都为 controlling 或者 controlled 角色冲突时,在连通性检查阶段,要求发送信息 binding request 消息中必须要带上 tie-breaker 属性
当出现冲突时,比较 tie-breaker 大小,值比较大的则被认为是 controlling,同时回应 487 错误给对端,对端收到消息 487 错误后切换角色
收集 candidates
客户端无法知道自己的外网 IP,需要发送 stun 包给 stun 服务,stun 服务返回对应客户端的出口 IP 和端口,返回来的地址和自己本地地址做比对便可以知道 NAT 类型
根据 Componet ID,获取本机 host address;从 STUN 服务器获取 srvflx address;从 TURN 服务器获取 relay address;同时生成 foundation;
删除重复的 candidate 收集地址完成后,需要去掉重复的 candidate,如果两个 candidate 的地址一样,并且 Base 地址也一样则删除
交换 candidates
ICE 交换 candidates 方式可以使用 sdp 交换,也可以使用单独信令交换
ICE 交换 candidates sdp 方式
ICE 使用 offer/answer 方式,双方通过 SDP 协商交换 candidate 信息;
Candidate 信息包括 type, foundation, base, component id, transport
SDP 示例
生成 candidate pairs
在本端收到远端 candidates 后,将 Component ID 和 transport protocol 相同的 candidates 组成 pair
修整 candidate pair,如果是 srvflx 地址则需要用其 base 地址替换
连通性检查
将 candidate pairs 按照优先级排序,供连通性检查使用,其实就是把 sdp 中的 candidate 地址和本地的 candidate 地址进行排队,组成一个 checklist 表,生成按优先级排序的链表,按优先顺序发起每个候选地址对的检查;
连通性检查成功的 candidate pair 按优先级排序的链表,用于 ICE 提名和选择最终路径,连通性检查完毕后,开始进行优先级排序
如果 checklist 中存在 relay candidate,则必须先为 relay candidate 创建 permission;permission 就是一个许可,如果没有创建许可,发送的包将被丢弃 (针对 TURN 时使用)
ICE 使用 STUN binding request/response,包含 Fingerprint 检验校验机制
如果 A 收到 B 的 response 则代表连通性检查成功,否则需要进行重传直到超时,在建立连接时,如果没有响应,则会以 RTO 时间进行重传,每次翻倍,直到最大重传次数;
STUN 请求采用 STUN short-term credential 方式认证,即一段时间如果没有 stun 包发送时,该连接会过期失效,因此需要不断地发送 stun 包并收到回复的 stun 包,用来保持连接有效性;刚开始建联时,以 50ms 间隔频率发送,后期稳定后是以 2.5s 的间隔频率发送,维持连接的有效性
STUN USERNAME 属性 ”RemoteUsername : localUsername”
两端在 SDP 协商时交换 ice-pwd 和 ice-ufrag,以得对端用户名和密码,计算 stun 包中的 MESSAGE-INTEGRITY 时,需要自己本地的 ice-pwd 去计算 Hmac-SHA1,生成对应的属性值串,用来检查消息的完整性
生成 validlist
将连通性检查成功的 candidate pair 按优先级排序加入 validlist,此时本地 candidate 填写的是公网映射地址,remote candidate 填写的是对端发送的 STUN binding request 地址
提名 candidate pair
由 controlling 提名哪对 candidate pair 为 valid pair
提名方式分为普通提名和进取型提名
普通提名方式会做两次连通性检查,在第一次做连通性检查时不会带上 USE-CANDIDATE 属性,而是在生成的 validlist 中选择 pair 再进行一次连通性检查,这时会带上 USE-CANDIDATE 属性,并且置位 nominated flag (ICE 提名地址对)
进取型方式则是每次发送连通性检查时都会带上 USE-CANDIDATE 属性,并且置位 nominated flag (ICE 提名地址对),不会再去做第二次连通性检查
选择最终传输地址
ICE 在提名的 valid pair 中选择优先级最高的那对作为本次 ICE 流程传输地址,然后开始建立 DTLS 连接,开始握手,交换证书
如果 A 收到 B 的 response,则代表连通性检查成功,否则需要进行重传直到超时
在建立连接时,如果没有响应,则会以 RTO 时间进行重传,每次翻倍,直到最大重传次数
STUN 请求,采用 STUN short-term credential 方式认证
STUN USERNAME 属性 ”
RemoteUsername:localUsername”
两端在 SDP 协商时交换 ice-pwd 和 ice-ufrag,以得对端用户名和密码
STUN 检查请求中需要检查地址的对称性,请求的源地址是响应的目的地址,请求的目的地址是响应的源地址,否则都设置状态为 Failed
ICE 的完整实现过程
1. 为中继候选地址生成许可 (Permissions)
2. 从本地候选往远端候选发送 Binding Request
在 Binding 请求中通常需要包含特殊的属性,以在 ICE 进行连接性检查的时候提供必要信息
PRIORITY 和 USE-CANDIDATE
终端必须在其 request 中包含 PRIORITY 属性,指明其优先级,优先级由公式计算获得;如果有需要也可以给出特别指定的候选 (即 USE-CANDIDATE 属性)
ICE-CONTROLLED 和 ICE-CONTROLLING
在每次会话中,每个终端都有一个身份,存在两种身份,即受控方(controlled role) 和主控方(controlling role),主控方负责选择最终用来通讯的候选地址对,受控方被告知哪个候选地址对用来进行哪次媒体流传输,并且不生成更新过的 offer 来提示此次告知;发起 ICE 处理进程 (即生成 offer)的一方必须是主控方,而另一方则是受控方;如果终端是受控方,那么在 request 中就必须加上 ICE-CONTROLLED 属性;如果终端是主控方,就需要 ICE-CONTROLLING 属性
生成 Credential
作为连接性检查的 Binding Request 必须使用 STUN 的短期身份验证;验证的用户名被格式化为一系列 username 段的联结,包含了发送请求的所有对等端的用户名,以冒号隔开;密码就是对等端的密码
3. 处理 Response
当收到 Binding Response 时,终端会将其与 Binding Request 相联系,通常通过事务 ID;随后将会将此事务 ID 与候选地址对进行绑定
终端收到成功响应之后,先检查其 mApped address 是否与本地记录的地址对有匹配,如果没有则生成一个新的候选地址,即对等端的反射地址;如果有匹配,则终端会构造一个可用候选地址对 (valid pair);
通常很可能地址对不存在于任何检查列表中,此时检索检查列表中没有被服务器反射的本地地址,将这些地址的本地候选转换成服务器反射地址的基地址并把冗余的地址去除掉;
失败响应
如果 STUN 传输返回 487(Role Conflict) 错误响应,终端首先会检查其是否包含了 ICE-CONTROLLED 或 ICE-CONTROLLING 属性;如果有 ICE-CONTROLLED 终端必须切换为 controlling role; 如果请求包含 ICE-CONTROLLING 属性则必须切换为 controlled role;切换完成,终端必须将使得产生 487 错误的候选地址对放入检查队列中,并将此地址对的状态设置为 Waiting
成功响应,一次连接检查在满足下列所有情况时候就被认为成功
STUN 传输产生一个 Success Response
response 的源 IP 和端口等于 Binding Request 的目的 IP 和端口
response 的目的 IP 和端口等于 Binding Request 的源 IP 和端口