为什么WebRTC需要一个专用的子系统来连接?
目前部署的大多数应用程序都建立客户端/服务器连接。客户端/服务器连接要求服务器具有稳定的已知传输地址。客户端联系服务器,服务器响应。
WebRTC不使用客户端/服务器模型,它建立点对点(P2P)连接。在 P2P 连接中,创建连接的任务平均分配给两个对等方。这是因为WebRTC中的传输地址(IP和端口)是无法假设的,甚至可能在会话期间发生变化。WebRTC将收集它所能收集的所有信息,并将竭尽全力实现两个WebRTC代理之间的双向通信。
不过,建立点对点连接可能很困难。这些代理可能位于没有直接连接的不同网络中。在确实存在直接连接的情况下,您仍然可能遇到其他问题。在某些情况下,您的客户端不使用相同的网络协议(UDP <-> TCP),或者可能使用不同的 IP 版本(IPv4 <-> IPv6)。
尽管在建立P2P连接时存在这些困难,但由于WebRTC提供的以下属性,您获得了优于传统客户端/服务器技术的优势。
降低带宽成本
由于媒体通信直接发生在对等方之间,因此您无需付费,也无需托管单独的服务器来中继媒体。
更低的延迟
直接沟通更快!当用户必须通过您的服务器运行所有内容时,它会使传输速度变慢。
安全的 E2E 通信
直接通信更安全。由于用户不会通过您的服务器路由数据,因此他们甚至不需要相信您不会解密它。
它是如何工作的?
上述过程称为交互式连接建立 ICE,另一个早于WebRTC的协议。
ICE 是一种协议,它试图找到在两个 ICE 代理之间进行通信的最佳方式。每个 ICE 代理都会发布其可访问的方式,这些方式称为候选项。候选项本质上是代理的传输地址,它认为其他对等方可以访问该地址。然后,ICE确定候选人的最佳配对。
本章后面将更详细地介绍实际的 ICE 过程。要理解ICE存在的原因,了解我们正在克服的网络行为是有用的。
网络现实世界的限制
ICE就是要克服现实世界网络的限制。在我们探索解决方案之前,让我们先谈谈实际问题。
不在同一网络中
大多数时候,另一个WebRTC代理甚至不会在同一个网络中。典型的呼叫通常是在不同网络中的两个WebRTC代理之间进行的,没有直接连接。
下面是通过公共互联网连接的两个不同网络的图表。在每个网络中,您有两个主机。
对于同一网络中的主机,连接非常容易。沟通之间很容易做到!这两个主机可以在没有任何外部帮助的情况下相互连接。192.168.0.1 -> 192.168.0.2
但是,使用主机无法直接访问后面的任何内容。您如何区分后面和后面的相同 IP?它们是私有 IP!使用 的主机可以将流量直接发送到 ,但请求将就此结束。如何知道它应该将消息转发到哪个主机?
Router B
Router A
192.168.0.1
Router A
Router B
Router B
Router A
Router A
协议限制
某些网络根本不允许 UDP 流量,或者它们可能不允许 TCP。某些网络可能具有非常低的 MTU(最大传输单位)。网络管理员可以更改许多变量,这些变量会使通信变得困难。
防火墙/IDS 规则
另一个是“深度数据包检测”和其他智能过滤。某些网络管理员将运行尝试处理每个数据包的软件。很多时候,该软件不理解WebRTC,所以它会阻止它,因为它不知道该怎么做,例如,将WebRTC数据包视为未列入白名单的任意端口上的可疑UDP数据包。
NAT 映射
NAT(网络地址转换)映射是使WebRTC连接成为可能的魔力。这就是WebRTC允许完全不同的子网中的两个对等体进行通信的方式,解决了上面的“不在同一网络中”的问题。虽然它带来了新的挑战,但让我们首先解释一下 NAT 映射的工作原理。
它不使用中继、代理或服务器。我们再次拥有并且它们在不同的网络中。但是,流量完全流过。可视化它看起来像这样:Agent 1
Agent 2
要实现此通信,您需要建立 NAT 映射。代理 1 使用端口 7000 与代理 2 建立 WebRTC 连接。这将创建 的绑定。然后,这将允许代理 2 通过将数据包发送到 来到达代理 1。创建 NAT 映射(如本例所示)类似于在路由器中进行端口转发的自动版本。192.168.0.1:7000
5.0.0.1:7000
5.0.0.1:7000
NAT 映射的缺点是没有单一形式的映射(例如静态端口转发),并且网络之间的行为不一致。ISP和硬件制造商可能会以不同的方式做到这一点。在某些情况下,网络管理员甚至可能会禁用它。
好消息是,所有的行为都是可以理解和观察的,因此ICE代理能够确认它创建了NAT映射以及映射的属性。
描述这些行为的文档是 RFC 4787。
创建映射
创建映射是最简单的部分。当您将数据包发送到网络外部的地址时,将创建映射!NAT 映射只是由 NAT 分配的临时公共 IP 和端口。出站消息将被重写,使其源地址由新的映射地址提供。如果将消息发送到映射,它将自动路由回创建它的 NAT 内的主机。有关映射的细节是它变得复杂的地方。
映射创建行为
映射创建分为三个不同的类别:
独立于端点的映射
为 NAT 中的每个发送方创建一个映射。如果将两个数据包发送到两个不同的远程地址,则将重复使用 NAT 映射。两个远程主机将看到相同的源 IP 和端口。如果远程主机响应,则会将其发送回同一本地侦听器。
这是最好的情况。要使调用正常工作,至少一端必须是此类型。
地址相关映射
每次将数据包发送到新地址时,都会创建一个新映射。如果将两个数据包发送到不同的主机,将创建两个映射。如果将两个数据包发送到同一远程主机但不同的目标端口,则不会创建新的映射。
地址和端口相关映射
如果远程 IP 或端口不同,则会创建新映射。如果将两个数据包发送到同一远程主机,但目标端口不同,则将创建新的映射。
映射过滤行为
映射筛选是关于允许谁使用映射的规则。它们分为三个类似的分类:
独立于端点的筛选
任何人都可以使用该映射。您可以与多个其他对等方共享映射,它们都可以向其发送流量。
地址相关过滤
只有为其创建映射的主机才能使用该映射。如果将数据包发送到主机,则只能从同一主机获得响应。如果主机尝试将数据包发送到该映射,则会忽略该数据包。A
B
地址和端口相关过滤
只有为其创建映射的主机和端口才能使用该映射。如果将数据包发送到,则只能从同一主机和端口获得响应。如果尝试将数据包发送到该映射,则将忽略该数据包。
如果映射在 5 分钟内未使用,建议将其销毁。这完全取决于ISP或硬件制造商。
STUN
STUN(NAT的会话遍历实用程序)是一种专为使用NAT而创建的协议。这是另一种早于WebRTC(和ICE!)的技术。它由 RFC 8489 定义,也定义了 STUN 数据包结构。ICE/TURN也使用STUN协议。
STUN 很有用,因为它允许以编程方式创建 NAT 映射。在STUN之前,我们能够创建一个NAT映射,但我们不知道它的IP和端口是什么!STUN不仅使您能够创建映射,还为您提供详细信息,以便您可以与他人共享,以便他们可以通过您刚刚创建的映射将流量发送回给您。
让我们从STUN的基本描述开始。稍后,我们将扩展 TURN 和 ICE 的使用。现在,我们只描述请求/响应流来创建映射。然后我们将讨论如何获取它的详细信息以与他人分享。这是当您在WebRTC PeerConnection的ICE URL中有一个服务器时发生的过程。简而言之,STUN通过要求NAT外部的STUN服务器报告它观察到的内容,帮助NAT后面的端点找出创建的映射。
协议结构
每个 STUN 数据包都具有以下结构:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0 0| STUN Message Type | Message Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Magic Cookie |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| Transaction ID (96 bits) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
眩晕消息类型
每个 STUN 数据包都有一个类型。目前,我们只关心以下内容:
- 具有约束力的请求 -
0x0001
- 绑定响应 -
0x0101
为了创建 NAT 映射,我们制作了一个 .然后服务器以 .Binding Request
Binding回应。
消息长度
这是该部分Data
的长度。本节包含由 Message Type
定义的任意数据。
魔术饼干
网络字节顺序中的固定值0x2112A442
,它有助于将STUN流量与其他协议区分开来。
交易编号
唯一标识请求/响应的 96 位标识符。这有助于您将请求和响应配对。
数据
数据将包含 STUN 属性列表。STUN属性具有以下结构:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Value (variable) ....
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
创建 NAT 映射
使用 STUN 创建 NAT 映射只需发送一个请求!您向 STUN 服务器发送STUN Binding Request
。然后,STUN 服务器以 STUN Binding Response回应
. 这STUN Binding Response
将包含Mapped Address
.这Mapped Address
就是 STUN 服务器看待您的方式,也是您的NAT mapping
. 如果您希望有人向您发送数据包,这Mapped Address
就是您将共享的内容。
人们也会称Mapped Address
您的.Public IP
或Server Reflexive Candidate
确定 NAT 类型
不幸的是,这Mapped Address
可能并非在所有情况下都有用。如果是Address Dependent
,则只有 STUN 服务器可以将流量发送回给您。如果您共享了它,并且另一个对等方尝试在其中发送消息,它们将被丢弃。这使得它对与他人交流毫无用处。您可能会发现Address Dependent
这种情况实际上是可以解决的,如果运行STUN服务器的主机也可以为您转发数据包到对等方!这将我们使用下面的 TURN 找到解决方案。
RFC 5780 定义了运行测试以确定 NAT 类型的方法。这很有用,因为您可以提前知道是否可以直接连接。
TURN
RFC 8656 中定义的 TURN(在 NAT 周围使用中继进行遍历)是无法直接连接时的解决方案。这可能是因为您有两种不兼容的 NAT 类型,或者可能无法使用相同的协议!TURN也可用于隐私目的。通过TURN运行所有通信,您可以模糊客户的实际地址。
TURN使用专用服务器。此服务器充当客户端的代理。客户端连接到 TURN 服务器并创建一个 Allocation
.通过创建分配,客户端将获得可用于将流量发送回客户端的临时 IP/端口/协议。此新侦听器称为 Relayed Transport Address
.把它想象成一个转发地址,你把它拿出来,这样其他人就可以通过TURN向你发送流量!对于您提供Relay Transport Address
给的每个对等方,您必须创建一个新的Permission
对等方以允许与您通信。
当您通过 TURN 发送出站流量时,它将通过Relayed Transport Address
.当远程对等体获得流量时,他们会看到它来自 TURN 服务器。
回合生命周期
以下是希望创建 TURN 分配的客户必须执行的所有操作。与使用 TURN 的人进行通信不需要更改。另一个对等方获得一个 IP 和端口,它们像任何其他主机一样与之通信。
分配
分配是TURN的核心。一次allocation
基本上是一个“TURN会话”。要创建 TURN 分配,您需要与 TURN Server Transport Address
(通常是端口3478)进行通信。
创建分配时,您需要提供以下内容:
- 用户名/密码 - 创建 TURN 分配需要身份验证。
- 分配传输 - 服务器 (
Relayed Transport Address
) 和对等方之间的传输协议可以是 UDP 或 TCP。 - 偶数端口 - 您可以为多个分配请求顺序端口,与WebRTC无关。
如果请求成功,您将在“数据”部分中收到具有以下 STUN 属性的 TURN 服务器的响应:
XOR-MAPPED-ADDRESS
-Mapped Address
的TURN Client
.当有人将数据发送到Relayed Transport Address
这是转发到的地方。RELAYED-ADDRESS
- 这是您提供给其他客户的地址。如果有人向此地址发送数据包,则会将其中继到 TURN 客户端。LIFETIME
- 此回合分配被销毁还有多长时间。您可以通过发送Refresh
请求来延长生存期。
权限
在您为远程主机创建权限之前,远程主机无法发送到您的主机Relayed Transport Address
。创建权限时,您告诉 TURN 服务器允许此 IP 和端口发送入站流量。
远程主机需要为您提供 TURN 服务器显示的 IP 和端口。这意味着它应该向 TURN 服务器发送 a STUN Binding Request
。一个常见的错误情况是远程主机将STUN Binding Request
发送到其他服务器。然后,他们会要求您为此 IP 创建权限。
假设您要为Address Dependent Mapping
后面的主机创建权限。如果从其他 TURN 服务器生成Mapped Address
,则将丢弃所有入站流量。每次它们与不同的主机通信时,都会生成一个新的映射。如果未刷新权限,则权限将在 5 分钟后过期。
发送指示/通道数据
这两条消息供 TURN 客户端将消息发送到远程对等方。
发送指示是一个独立的消息。里面是您希望发送的数据,以及您希望将其发送给谁。如果您要向远程对等方发送大量消息,这是浪费。如果您发送 1,000 条消息,您将重复其 IP 地址 1,000 次!
通道数据允许您发送数据,但不能重复 IP 地址。创建具有 IP 和端口的通道。然后,使用 ChannelId 发送,IP 和端口将在服务器端填充。如果您要发送大量消息,这是更好的选择。
刷新
分配将自动销毁。创建分配时,TURN 客户端必须比给定的LIFETIME
刷新它们更快。
TURN用法
TURN 用法以两种形式存在。通常,您有一个对等方充当“TURN客户端”,另一端直接通信。在某些情况下,您可能在两端都使用 TURN,例如,因为两个客户端都在阻止 UDP 的网络中,因此与相应 TURN 服务器的连接是通过 TCP 进行的。
这些图表有助于说明它的外观。
用于通信的TURN分配
两个用于通信的 TURN 分配
ICE
ICE(交互式连接建立)是WebRTC连接两个代理的方式。在RFC 8445中定义,这是WebRTC之前的另一种技术!ICE是用于建立连接的协议。它确定两个对等体之间的所有可能路由,然后确保您保持连接。
这些路由称为Candidate Pairs
,它是本地和远程传输地址的配对。这就是STUN和TURN与ICE发挥作用的地方。这些地址可以是您的本地 IP 地址加上端口、NAT mapping
、或 Relayed Transport Address
。每一方都收集他们想要使用的所有地址,交换它们,然后尝试连接!
两个 ICE 代理使用 ICE ping 数据包(或正式称为连接检查)进行通信以建立连接。建立连接后,他们可以发送所需的任何数据。这就像使用普通套接字一样。这些检查使用 STUN 协议。
创建 ICE 代理
ICE 代理是Controlling
或 Controlled
。Controlling
代理是决定所选Candidate Pair
.通常,发送报价的对等方是控制方。
每一端都必须有一个user fragment
和一个password
.在开始连接检查之前,必须交换这两个值。user fragment
以纯文本形式发送,对于解复用多个 ICE 会话非常有用。 password
用于生成MESSAGE-INTEGRITY
属性。在每个 STUN 数据包的末尾,都有一个属性,该属性是使用 password
作为键的整个数据包的哈希。这用于对数据包进行身份验证并确保它未被篡改。
对于WebRTC,所有这些值都是通过上一章Session Description
中所述的分布的。
候选人合集
我们现在需要收集所有可能的地址。这些地址称为候选项。
主机
主机候选项正在直接侦听本地接口。这可以是UDP或TCP。
移动域名系统
mDNS 候选项类似于主机候选项,但 IP 地址被遮盖。您不会通知对方您的 IP 地址,而是给他们一个 UUID 作为主机名。然后,设置多播侦听器,并在有人请求您发布的 UUID 时做出响应。
如果您与代理位于同一网络中,则可以通过多播找到彼此。如果您不在同一网络中,您将无法连接(除非网络管理员明确配置网络以允许遍历组播数据包)。
这对于隐私目的很有用。用户可以通过WebRTC找到您的本地IP地址,使用主机候选(甚至无需尝试连接到您),但是使用mDNS候选,现在他们只能获得随机UUID。
服务器自反
服务器反射候选项是通过对 STUN 服务器执行 a STUN Binding Request
来生成的。
当您获得STUN Binding Response
时,XOR-MAPPED-ADDRESS
是您的服务器反身候选项。
对等方反身
当远程对等方从对等方以前未知的地址接收您的请求时,将创建对等反射候选项。收到后,同行会向您报告(反映)所述地址。对等方知道请求是由您而不是其他人发送的,因为 ICE 是经过身份验证的协议。
当 Host Candidate
与位于不同子网中的 a Server Reflexive Candidate
通信时,通常会发生这种情况,这会导致创建新的子网NAT mapping
。还记得我们说过连接检查实际上是 STUN 数据包吗?STUN响应的格式自然允许对等方报告对等反射地址。
中继
中继候选项是使用 TURN 服务器生成的。
在与 TURN 服务器进行初始握手后,您将获得一个RELAYED-ADDRESS
,这是您的中继候选者。
连接性检查
我们现在知道远程代理的user fragment
、password
和候选项。我们现在可以尝试连接了!每个候选人都相互配对。因此,如果每边有 3 个候选人,那么您现在有 9 个候选人对。
视觉上它看起来像这样:
候选人选择
控制代理和受控代理都开始在每对上发送流量。如果一个代理位于Address Dependent Mapping
后面,则需要这样做,这将导致创建Peer Reflexive Candidate
。
然后,每个Candidate Pair
看到网络流量的人都会提升为一对Valid Candidate
。然后,控制代理选取一对Valid Candidate
并指定它。这将成为Nominated Pair
.然后,控制和受控代理再尝试一轮双向通信。如果成功,Nominated Pair
则变为 Selected Candidate Pair
!然后,此对将用于会话的其余部分。
重新 启动
如果 NAT 因任何原因Selected Candidate Pair
停止工作(NAT 映射过期,TURN 服务器崩溃),ICE 代理将进入Failed
状态。两个代理都可以重新启动,并将重新执行整个过程。