WebRTC 中的 ICE 实现

WebRTC 中的 ICE 实现

Candidate 种类与优先级

ICE中使用的Candidate具有优先级次序,由高到低分别为host、srflx、prflx、relay。WebRTC进行一对一音视频通信时,就是按照这个次序尝试建立连接的。

WebRTC通信时会按照内网、P2P、relay这样的次序尝试连接:

  1. 内网连接对应host连接策略。host连接表示直接在本地设备上建立的连接,也就是在同一局域网内的设备之间的直接连接。
  2. 不在同一局域网内,双方尝试host型Candidate连接时会失败。不过,在双方尝试连接时,双方Candidate的收集工作并未停止。Candidate收集线程还在收集其他类型的Candidate,如从STUN/TURN服务器收集srflx和relay类型的Candidate。
  3. P2P连接对应srflx和prflx连接策略。srflx(server reflexive)和prflx(peer reflexive)连接都是通过STUN服务器获取的公共IP地址,用于建立点对点连接。srflx连接是通过NAT后的公共IP地址建立的连接(当收集到srflx类型的Candidate时,ICE会尝试NAT打洞),而prflx连接是对等方自己的NAT映射地址。
  4. 中继连接对应relay连接策略。当无法建立直接的P2P连接时,WebRTC会使用TURN服务器作为中继,建立relay连接。relay连接通过中继服务器传递数据,确保数据的可靠传输。

请添加图片描述

总结:

  • WebRTC的ICE机制会选择最好的链路传输音视频数据,即如果通信的双方在同一网段内,则优先使用内网链路;如果通信的双方不在同一网段,则优先使用P2P;当以上方式都无法连通时,则使用relay服务进行中转。
  • ICE的连通率几乎可以达到100%。在内网和P2P无法连通的情况下,它还可以通用中继的方式让彼此连通,从而大大提高了WebRTC的连通率。

WebRTC中的ICE既考虑了数据传输的效率,又考虑了网络的连通率,实现起来也简单。

ICE 策略

RTCPeerConnection提供了一种在浏览器之间建立点对点连接的方式,而无需通过服务器进行中转。它使用了ICE(Interactive Connectivity Establishment,交互式连接创建)协议来处理网络地址和端口的自动配置,以确保连接的稳定性和可靠性。

构造RTCPeerConnection对象时,其输入参数的类型为RTCConfiguration。参数 configuration 是一个 JSON 对象,用于提供配置新连接的选项。

在这里插入图片描述

下面是 RTCConfiguration 各字段的含义:

在这里插入图片描述

iceServers是RTCIceServer类型的数组,可以包含一个或多个STUN和/或TURN服务器。

dictionary RTCIceServer {
	required (DOMString or sequence<DOMString>) urls;
	DOMString username;
	DOMString credential;
	RTCIceCredentialType credentialType = "password";
};

各字段含义:

  1. url:服务器地址;
  2. username:访问该服务器时使用的用户名;
  3. credential:访问该服务器时使用的密码;
  4. credentialType:指明授权方式为密码方式,也是目前唯一的授权方式。

更详细的介绍:WebRTC 的核心:RTCPeerConnection

RTCConfiguration 实例:

RTCConfiguration pcConfig = {
   'iceServers': [{
      'urls': 'turn:stun.learningrtc.cn:3478',
      'username': "username1",
      'credential': "password1",
   },{
      'urls': 'turn:stun.avdancedu.com:3478',
      'username': "username2",
      'credential': "password2",
   }],
   'iceTransportPolicy': "all",
   'bundlePolicy': "max-bundle",
   'rtcpMuxPolicy': "require"
};
RTCPeerConnection pc = new RTCPeerConnection(pcConfig);

解释:

  1. iceServers 包含两个 TURN 服务器,相当于为 WebRTC 增加了两个 relay 类型的 Candidate。当内网和P2P无法连通时,RTCPeerConnection 会尝试与这两台中继服务器连接。如果其中一台连接成功,就不会尝试另一台。
  2. iceTransportPolicy 为 “all”,表示所有的 ICE 候选都会被考虑,按 Candidate 的优先级次序尝试连接。
  3. bundlePolicy 为 “max-bundle”,所有媒体数据使用同一个 Candidate,这样更有利于端口资源的利用。
  4. rtcpMuxPolicy 为 “require”,表示 RTCP 和 RTP 数据共用一个 Candidate。

P2P 连接

这里的 P2P 指的就是如何进行 NAT 穿越。NAT在真实的网络环境中随处可见,它的出现主要出于两个目的:

  1. 为了解决IPv4地址不够用的问题。当时IPv6短期内还无法替换IPv4,而IPv4的地址又特别紧缺,所以人们想到让多台主机共用一个公网IP地址,大大减缓了IPv4地址不够用的问题。
  2. 为了解决安全问题。使用NAT后,主机隐藏在内网,这样黑客就很难访问到内网主机,从而达到保护内网主机的目的。

请添加图片描述

NAT就是一种地址映射技术,它在内网地址与外网地址之间建立了映射关系。当内网主机向外网主机发送信息时,数据在经过NAT层时,NAT会将数据包头中的源IP地址和源端口号替换为映射后的外网IP地址和外网端口。相反,当接收数据时,NAT收到数据后会将目标地址映射为内网的IP地址和端口再转给内网主机。

请添加图片描述

RFC3489和RFC5389是最重要的两份NAT穿越的协议文档。在RFC3489协议中,将NAT分成4种类型,即完全锥型、IP限制锥型、端口限制锥型以及对称型。在这4种类型中,越往后的NAT类型穿越难度越大。

大多数情况下NAT穿越使用的是UDP,这是因为UDP是无连接协议的,打洞会更加方便。当然,也可以使用TCP打洞。

完全锥型 NAT

完全锥型NAT的特点:一旦打洞成功,所有知道该洞的主机都可以通过它与内网主机进行通信。

当 host 主机通过 NAT 访问外网主机 B 时,就会在 NAT 上打洞。如果主机 B 将该洞的信息分享给主机 A 和 C,那么它们也可以通过该洞给内网的 host 主机发送消息。

在这里插入图片描述

“洞”就是 NAT 上的一个内外网的映射表,其格式为:{内网IP,内网端口号,外网IP,外网端口号}。有了这个映射表,所有发向洞的数据都会被 NAT 中转到内网的 host 主机。在 host 主机上,所有侦听其内网端口的应用程序可以收到所有发向它的数据。

IP 限制锥型 NAT

IP限制锥型NAT要比完全锥型NAT严格得多。IP限制锥型NAT的主要特点:NAT打洞成功后,只有与之打洞成功的外网主机才能通过该洞与内网主机通信,而其他外网主机即使知道洞口也不能与之通信。

在这里插入图片描述

只有 host 主机访问过的外网主机才能穿越这个洞。

IP 限制锥型 NAT 的映射表是一个五元组,其格式为:{内网IP,内网端口号,外网IP,外网端口号,[被访问主机的IP,…]}。当外网主机通过 IP 限制锥型 NAT 向内网主机发送消息时,NAT 会检测数据包头的源 IP 地址是否在 NAT 映射表中有记录。如果有,说明是合法数据,可以进行数据转发;如果没有记录,说明非法,NAT 将该数据包直接丢弃。

端口限制锥型 NAT

端口限制锥型NAT的主要特点:除了像IP限制锥型NAT一样需要对IP地址进行检测外,还需要对端口进行检测。

在这里插入图片描述

端口限制锥型 NAT 的映射表是一个五元组,其格式为:{内网IP,内网端口号,外网IP,外网端口号,[{被访问主机的IP,被访问主机的端口},…]}。

对称型 NAT

对称型NAT是4种NAT类型中对数据包检测最严格的。对称型NAT的特点:内网主机每次访问不同的外网主机时,都会生成一个新洞,而不像前面3种NAT类型使用的是同一个洞。

请添加图片描述

对称型NAT的映射表是一个六元组,其格式为:{内网IP,内网端口号,外网IP,外网端口号,被访问主机的IP,被访问主机的端口}。

对称型NAT每次访问不同外网主机都生成新洞的这种特性,导致对称型NAT碰到对称型NAT或者对称型NAT遇到端口限制型NAT时,双方打洞的成功率非常低,即使可以互通,成本也非常高。WebRTC遇到上面这两种情况时,直接放弃打洞的尝试。

NAT 类型检测

RFC3489 协议中给出了标准的 NAT 类型检测流程:

请添加图片描述

内网主机进行 NAT 类型检测时,需要两台 STUN 服务器,每台 STUN 服务器又需要两块网卡,每块网卡需要配置公网 IP 地址。

检测过程:

  1. 检测是否在NAT之后或者UDP socket是否阻塞
    向IP1:PORT1发送数据包,要求IP1:PORT1返回数据包源地址和端口号,同时设置socket timeout,重复一定次数后,如果一直未收到数据包回复,表明UDP通信被阻塞。如果收到数据包,和自身的IP:port对比,如果相同,则表明没有经过NAT,不同则表明一个是外网IP,一个是内网IP,且经过NAT设备。

  2. 检测是否为完全锥形NAT
    向IP1:port1发送数据包,要求IP2:port2向目的主机发送数据包,如果目的主机可以接收,表明是完全锥形NAT.

  3. 检测是否为对称形NAT
    向IP2:port2发送数据包,要求返回数据包的外网地址和端口号,将其与步骤2的外网地址和端口号对比,如果完全相同,则为限制锥形NAT或者端口限制NAT,否则为对称形NAT。

  4. 检测是否为限制锥形NAT或者端口限制NAT
    向IP2:port2发送数据包,由IP2:port3向源地址返回数据,如果可以收到,表明为限制锥形,否则为端口和IP限制锥形。

如何进行 NAT 穿越

各 NAT 之间可穿越表:

NAT 类型NAT 类型能否穿越
完全锥型 NAT完全锥型 NAT可以
完全锥型 NATIP 限制锥型 NAT可以
完全锥型 NAT端口限制锥型 NAT可以
完全锥型 NAT对称型 NAT可以
IP 限制锥型 NATIP 限制锥型 NAT可以
IP 限制锥型 NAT端口限制锥型 NAT可以
IP 限制锥型 NAT对称型 NAT可以
端口限制锥型 NAT端口限制锥型 NAT可以
端口限制锥型 NAT对称型 NAT不可以
对称型 NAT对称型 NAT不可以

可以看出,完全锥型 NAT 和 IP 限制锥型 NAT 可以与其他任何类型的 NAT 互通。而最后两种情况因为互通成本太高,不必尝试 NAT 穿越。

网络中继

当遇到NAT之间无法打通的情况时,WebRTC会使用TURN协议通过中转的方式实现端与端之间的通信。

TURN 协议中转数据

TURN协议采用了典型的客户端/服务器模式,其服务器端称为TurnServer,客户端称为TurnClient。TurnClient与TurnServer之间通过信令控制数据流的发送。

TURN协议底层依赖于STUN协议。值得一提的是,TURN协议本身是STUN协议的一个拓展,因此绝大部分TURN报文都是STUN类型的,作为STUN的一个拓展,TURN增加了新的方法(method)和属性(attribute)。

下图就是一个 TURN 服务中转的实例,有个TURN client端和一个TURN Server端以及两个Peer对端。

在这里插入图片描述

在上图中,左边的 TurnClient 是位于 NAT 后面的一个客户端(内网地址是10.1.1.2:49721)。TurnClient 首先向 TurnServer 的 3478 端口发送 Allocate 指令。TurnServer 收到该消息后,在 TurnServer 分配一个与 TurnClient 对应的 Relay 地址(192.0.2.15:50000),任何发向 Relay 地址的数据都会被转发到 TurnClient 端。

主机 A 和 B 不是 TurnClient,它们被称为 Peer 端。Peer 端可以使用 UDP 向 TurnServer 的 Relay 地址发送数据,TurnServer 根据映射关系,将 Relay 地址收到的数据转给对应的 TurnClient。

注意,TurnClient 和 TurnServer 之间的传输协议可以是 UDP 或者 TCP。而在 TurnServer 上分配的 Relay 地址使用的都是 UDP。

TurnServer 上的每一个 allocation 都唯一对应一个 TurnClient,并且只有一个中继地址,因此当数据包到达某个中继地址时,服务器总是知道应该将其转发到什么地方。
但值得一提的是,一个 TurnClient 可能在同一时间在一个 TurnServer 上会有多个 allocation,这和上述规则是并不矛盾的。

TURN 协议对应端到端传输数据提供了 2 种方法:

  1. Send/Data indication:指令 Send indication(XOR-PEER-ADDRESS、DATA) 用于 TurnClient 向某个 Peer 端发数据,其中 XOR-PEER-ADDRESS 属性用于指定向哪个主机转发数据,DATA 属性指明数据的具体内容。相反,当 Peer 端通过 TurnServer 向 TurnClient 发数据时,使用 Data indication 指令,指明向哪个 TurnClient 转发数据。
  2. tunnel机制:使用tunnel机制的好处是不用再像使用Send/Data indication指令一样,每次都要指定数据发往的地址,只需要在开始发送数据之前,发送ChannelBind指令将channel number与目标地址绑定一次即可,后面统一使用channel number就可以找到发往的目的地。

WebRTC 使用 TURN 协议

WebRTC 收集到的 relay 类型 Candidate,指的就是通过 TURN 协议的 Allocation 指令分配的地址。

WebRTC通信的两端既是 TurnClient,因此都可以使用 TURN 协议与 TurnServer 建立联系;又是彼此的 Peer 端,因此可以向对端的 Relay 地址发送数据,从而让 TurnServer 将数据中转给对端。

在这里插入图片描述

3478 是一个多路复用的端口:

  1. 接收 Allocate 指令:TurnClient 首先向 TurnServer 的 3478 端口发送 Allocate 指令。TurnServer 收到该消息后,在 TurnServer 分配一个与 TurnClient 对应的 Relay 地址。
  2. TurnServer 从 Relay 地址收到数据后,将其打包成 TURN 消息,也要经过 3478 端口转发给对应 TurnClient。

STUN/TURN 服务器的安装与部署

公网上的 STUN/TURN 服务器的安装与部署一般采用云主机。目前比较流行的是 Google 开源的 coturn 服务器。

基本步骤:

  1. 获取 coturn 源码:https://github.com/coturn/coturn。
  2. 编译安装。
  3. 配置 coturn:配置一下侦听的端口(默认为 3478)、指定云主机的公网 IP 地址、访问 STUN/TURN 服务的用户名和密码。
  4. 启动 STUN/TURN 服务。
  5. 测试 STUN/TURN 服务:打开trickle-ice 测试工具,按要求输入 STUN/TURN 地址、用户名和密码就可以探测 STUN/TURN 服务运行是否正常。

STUN/TURN 部署好后,就可以使用它转发多媒体数据,不用担心通信双方因 NAT 或防火墙等原因而无法通信的问题。

  • 22
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值