# WebRTC(八)如何建立连接

# 连接建立的基本原则

接下来,我将通过两个具体的场景,向你介绍一下 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
...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  • 其中,候选者类型中的 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。

Last Updated: 2/13/2023, 9:16:34 PM