连接建立的基本原则
接下来,我将通过两个具体的场景,向你介绍一下 WebRTC 建立连接的基本原则。不过在讲解之前,我们先设置一些假设条件,这样会更有利于我们下面的描述:
- 通信的双方我们称为 A 和 B;
- A 为呼叫方,B 为被呼叫方;
- C 为中继服务器,也称为 relay 服务器或 TURN 服务器。
1. 场景一:双方处于同一网段内
A 与 B 进行通信,假设它们现在处于同一个办公区的同一个网段内。在这种情况下,A 与 B 有两种连通路径:
-
一种是双方通过内网直接进行连接;
-
另一种是通过公网,也就是通过公司的网关,从公网绕一圈后再进入公司实现双方的通信。
相较而言,显然第一种连接路径是最好的。 A 与 B 在内网连接就好了,谁会舍近求远呢?
2. 场景二:双方处于不同点
A 与 B 进行通信,它们分别在不同的地点,比如一个在北京,一个在上海,此时 A 与 B 通信必须走公网。但走公网也有两条路径:
-
一是通过 P2P 的方式双方直接建立连接;
-
二是通过中继服务器进行中转,即 A 与 B 都先与 C 建立连接,当 A 向 B 发消息时, A 先将数据发给 C,然后 C 再转发给 B;同理, B 向 A 发消息时,B 先将消息发给 C,然后 C 再转给 A。
对于这两条路径你该如何选择呢?对于 WebRTC 来讲,它认为通过中继的方式会增加 A 与 B 之间传输的时长,所以它优先使用 P2P 方式;如果 P2P 方式不通,才会使用中继的方式。
什么是 Candidate
ICE Candidate (ICE 候选者)。它表示 WebRTC 与远端通信时使用的协议、IP 地址和端口,一般由以下字段组成:
- 本地 IP 地址
- 本地端口号
- 候选者类型,包括 host、srflx 和 relay
- 优先级
- 传输协议
- 访问服务的用户名
- ……
代码表示:
{
IP: xxx.xxx.xxx.xxx,
port: number,
type: host/srflx/relay,
priority: number,
protocol: UDP/TCP,
usernameFragment: string
...
}
-
其中,候选者类型中的 host 表示本机候选者,srflx 表示内网主机映射的外网的地址和端口,relay 表示中继候选者。
-
在众多候选者中,host 类型的候选者优先级是最高的。在 WebRTC 中,首先对 host 类型的候选者进行连通性检测,如果它们之间可以互通,则直接建立连接。其实**,host 类型之间的连通性检测就是内网之间的连通性检测**。WebRTC 就是通过这种方式巧妙地解决了大家认为很困难的问题。
-
同样的道理,如果 host 类型候选者之间无法建立连接,那么 WebRTC 则会尝试次优先级的候选者,即 srflx 类型的候选者。也就是尝试让通信双方直接通过 P2P 进行连接,如果连接成功就使用P2P 传输数据;如果失败,就最后尝试使用 relay 方式建立连接。
收集 Candidate
了解了什么是 Candidate 之后,接下来,我们再来看一下端对端的连接是如何建立的吧。
实际上,端对端的建立更主要的工作是 Candidate 的收集。WebRTC 将 Candidate 分为三种类型:
host 类型,即本机内网的 IP 和端口;
srflx 类型, 即本机 NAT 映射后的外网的 IP 和端口;
relay 类型,即中继服务器的 IP 和端口。
其中,host 类型优先级最高,srflx 次之,relay 最低。
1. STUN 协议
- 在内网的网关上都有 NAT (Net Address Translation) 功能,NAT 的作用就是进行内外网的地址转换。这样当你要访问公网上的资源时,NAT 首先会将该主机的内网地址转换成外网地址,然后才会将请求发送给要访问的服务器;服务器处理好后将结果返回给主机的公网地址和端口,再通过 NAT 最终中转给内网的主机。
- 实际上,上面的描述已经被定义成了一套规范,即 RFC5389 ,也就是STUN 协议,我们只要遵守这个协议就可以拿到自己的公网 IP 了。
这里我们举个例子,看看通过 STUN 协议,主机是如何获取到自己的外网 IP 地址和端口的。
- 首先在外网搭建一个 STUN 服务器,现在比较流行的 STUN 服务器是 CoTURN,你可以到 GitHub 上自己下载源码编译安装。
- 当 STUN 服务器安装好后,从内网主机发送一个 binding request 的 STUN 消息到 STUN 服务器。
- STUN 服务器收到该请求后,会将请求的 IP 地址和端口填充到 binding response 消息中,然后顺原路将该消息返回给内网主机。此时,收到 binding response 消息的内网主机就可以解析 binding response 消息了,并可以从中得到自己的外网 IP 和端口。
2. TURN 协议
这里需要说明一点,relay 服务是通过 TURN 协议实现的。所以我们经常说的 relay 服务器或 TURN 服务器它们是同一个意思,都是指中继服务器。
relay 型候选者的优先级与其他类型相比是最低的,但在其他候选者都无法连通的情况下,relay 候选者就成了最好的选择。因为它的连通率是所有候选者中连通率最高的。
NAT 打洞 /P2P 穿越
WebRTC 将 NAT 分类为 4 种类型,分别是:
- 完全锥型 NAT
- IP 限制型 NAT
- 端口限制型 NAT
- 对称型 NAT
ICE
了解了上面的知识后,你再来看 ICE 就比较简单了。其实 ICE 就是上面所讲的获取各种类型 Candidate 的过程,也就是:在本机收集所有的 host 类型的 Candidate,通过 STUN 协议收集 srflx 类型的 Candidate,使用 TURN 协议收集 relay 类型的 Candidate。