【音视频第15天】webRTC协议(2)

原地址
https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Protocols

协议

ICE

Interactive Connectivity Establishment (ICE)是一个框架,能让web浏览器与对面进行连接。
从a端到b端不能直接建立连接原因有很多。

  1. 它需要绕过会阻止建立连接的防火墙
  2. 如果你的设备没有公共IP地址,那么它需要提供给你唯一的地址
  3. 如果你的路由器不允许直接与对端连接,那么需要通过服务器中转数据。
    ICE使用STUN和/或TURN服务器来完成此任务,如下所述。

STUN

Session Traversal Utilities for NAT (STUN)是一种协议,用于发现您的公共地址,并确定路由器中阻止与对端直接连接的任何限制。
客户端将向Internet上的STUN服务器发送一个请求,STUN服务器将回复客户端的公共地址以及在路由器的NAT之后是否可以访问客户端。
可以了就可以直接访问了。
在这里插入图片描述

NAT

Network Address Translation (NAT)用于为您的设备提供一个公共IP地址。路由器将有一个公共IP地址,连接到路由器的每个设备将有一个私有IP地址。请求将从设备的私有IP转换为路由器的具有唯一端口的公共IP。这样你就不用每个设备都有一个唯一的公共IP,但仍然可以在互联网上被发现。
对于谁能连接上已经在互联网上的设备,路由器对此有限制。这可能意味着,即使我们拥有STUN服务器找到的公共IP地址,也不是任何人都可以创建连接。在这种情况下,我们需要使用TURN。

TURN

一些使用NAT的路由器采用“对称NAT”的限制方法。这意味着路由器将只接受来自你之前连接过的对端的连接。【也就是在对称NAT下,只能连接之前连接了的对端】
Traversal Using Relays around NAT (TURN)意味着绕过对称NAT的限制,通过打开与TURN服务器的连接并通过该服务器中转所有信息。您将创建一个与TURN服务器的连接,并告诉所有对等点向服务器发送数据包,然后这些数据包将被转发给您。这显然会带来一些成本开销,所以只有在没有其他替代方案的情况下才会使用它。
在这里插入图片描述

SDP

Session Description Protocol (SDP)是一种标准,用于描述连接的多媒体内容,如分辨率、格式、编解码器、加密等,以便对等端在数据传输时能够相互理解。从本质上讲,这是描述内容的元数据,而不是媒体内容本身。
从技术上讲,SDP并不是真正的协议,而是一种用于描述设备间共享媒体的连接的数据格式
编写SDP文档远远超出了本文档的范围;然而,这里有一些事情值得注意:

SDP结构

SDP由一行或多行UTF-8文本组成,每行以一个字符类型开头,后面跟着等号(“=”),然后是包含值或描述的结构化文本,其格式取决于类型。以给定字母开头的文本行通常被称为“字母行”。例如,提供媒体描述的行具有“m”类型,因此这些行被称为“m-line”。

Signaling and Connecting

Signaling: How peers find each other in WebRTC

【通过带外的信令,传递SDP】
当WebRTC代理启动时,它不知道它要与谁通信,也不知道他们要通信什么。Signaling解决了这个问题。Signaling用于引导调用,允许两个独立的WebRTC代理开始通信。
Signaling使用一种称为SDP(会话描述协议)的协议。每个SDP消息由键/值对组成,并包含一个“media sections”列表。两个WebRTC代理交换的SDP包含如下细节:

  • 代理可访问的ip和ports
  • 代理希望发送的音频和视频轨道的数量。
  • 每个代理支持的音频和视频编解码器。
  • 连接时使用的值(uFrag/uPwd)。
  • 安全时使用的值(证书指纹)。
    需要注意的是,信令通常发生在“带外out-of-band”,这意味着应用程序通常不使用WebRTC本身来交换信令消息。任何适合于发送消息的体系结构都可以在连接的对等体之间中转sdp,许多应用程序将简单地使用它们现有的基础结构(例如REST端点、WebSocket连接或身份验证代理)来促进适当的客户机之间的sdp交易。

Connecting and NAT Traversal with STUN/TURN

【通过ICE建立连接】
一旦两个WebRTC代理交换了sdp,它们就有了足够的信息来尝试相互连接。为了实现这种连接,WebRTC使用了另一种称为ICE(交互式连接建立)的成熟技术。
ICE是一种早于WebRTC的协议,允许在没有中央服务器的情况下在两个代理之间建立直接连接。这两个代理可能在同一个网络上,也可能在世界的另一端。
ICE可以实现直接连接,但真正连接过程涉及一个叫做“NAT遍历”的概念和STUN/TURN服务器的使用。
当两个代理成功建立ICE连接时,WebRTC将进入下一步;为在它们之间共享音频、视频和数据建立加密传输。

Signaling

当您创建WebRTC代理时,它对另一个对端一无所知。它不知道它将与谁连接,也不知道他们将发送什么。我们使用信令引导调用。在这些值交换之后,WebRTC代理可以直接相互通信。信令信息只是文本。WebRTC并不关心他们是如何被运输的。它们通常通过Websockets共享,但这不是必需的。
WebRTC使用一种称为sdp协议。通过该协议,两个WebRTC端点将共享建立连接所需的所有状态。协议本身易于阅读和理解。复杂性来自于理解WebRTC填充的所有值**。这个协议不是专门针对WebRTC的**。WebRTC实际上只利用了sdp协议的一个子集,所以我们只学习我们需要的部分。在我们理解该协议之后,我们将继续讨论它在WebRTC中的应用。

sdp协议

sdp协议在RFC 8866中定义。它是一个键/值协议,每个值后面都有换行符。它感觉类似于INI文件。一个会话描述包含0个或多个媒体描述。在思想上,你可以把它建模为一个会话描述,其中包含一个媒体描述数组。
媒体描述通常映射到一个单一的媒体流。因此,如果你想用三个视频流和两个音频轨道来描述一个会话,你将有五个媒体描述。
会话描述中的每一行都以一个字符开始,这是你的键。然后它后面会跟着一个等号。等号后面就是值。在该值完成后,将有一个换行符。
会话描述协议定义了所有有效的密钥。您只能使用协议中定义的字母作为密钥。这些键都有重要的意义,后面会解释。以下会话描述:

a=my-sdp-value
a=second-value

你有两条线。第一行值为my-sdp-value,第二行值为second-value。
WebRTC并不使用会话描述协议定义的所有键值。只有在RFC 8829中定义的JavaScript会话建立协议(JSEP)中使用的键是重要的。下面的七个关键是你现在只需要了解的:

v - Version, should be equal to 0.
o - Origin, 包含一个唯一的ID,用于重新协商.
s - Session Name, should be equal to -.
t - Timing, should be equal to 0 0.
m - Media Description (m=<media> <port> <proto> <fmt> ...), described in detail below.
a - Attribute, 一个自由文本字段。这是WebRTC中最常见的一行。
c - Connection Data, should be equal to IN IP4 0.0.0.0.

“会话描述”可以包含无限个“Media Description”。
Media Description定义包含一个格式列表。这些格式映射到RTP有效负载类型。然后,实际的编解码器由Media Description中值为rtpmap的Attribute定义。每个媒体描述可以包含无限数量的属性。
以这段Session Description摘录为例:

v=0
m=audio 4000 RTP/AVP 111
a=rtpmap:111 OPUS/48000/2
m=video 4000 RTP/AVP 96
a=rtpmap:96 VP8/90000
a=my-sdp-value

您有两个媒体描述,一个是fmt 111类型的音频,一个是96格式的视频。第一个媒体描述只有一个属性。此属性将负载类型111映射到Opus。第二个Media Description有两个属性。第一个属性将Payload Type 96映射为VP8,第二个属性是my-sdp-value。
下面将我们讨论过的所有概念结合在一起。这些都是WebRTC使用的会话描述协议的所有特性。

v=0
o=- 0 0 IN IP4 127.0.0.1
s=-
c=IN IP4 127.0.0.1
t=0 0
m=audio 4000 RTP/AVP 111
a=rtpmap:111 OPUS/48000/2
m=video 4002 RTP/AVP 96
a=rtpmap:96 VP8/90000

v, o, s, c, t被定义,但它们不影响WebRTC会话。
你有两个媒体描述。一个是音频类型,一个是视频类型。
每一个都有一个属性。此属性配置RTP管道的详细信息。

WebRTC如何使用sdp

WebRTC使用offer/answer模型。这意味着一个WebRTC代理发出“offer”开始呼叫,如果它愿意接受所提供的内容,WebRTC 另一端“answers”。这使应答者有机会在媒体描述中拒绝不支持的编解码器。这就是两端如何理解它们想交换的格式。
Transceivers 是用于发送和接收的
Transceivers 是WebRTC特定的概念,你将在API中看到。它将“Media Description”暴露给JavaScript API。每个Media Description都成为一个Transceivers。每次你创建一个Transceivers,一个新的“Media Description就会被添加到本地Session Description中。WebRTC中的每个Media Description都有一个方向属性。这允许WebRTC代理声明“我将把这个编解码器发送给你,但我不愿意接受任何回报”。有四个有效值:send recv sendrecv inactive
WebRTC使用的SDP值
在WebRTC代理的会话描述中常见属性的列表。这些值控制着子系统。
group:BUNDLE:Bundling是在一个连接上运行多种类型的流量的行为。一些WebRTC实现为每个媒体流使用专用连接。最好是Bundling。
fingerprint:sha-256:这是对等体用于DTLS的证书的hash。DTLS握手完成后,将其与实际证书进行比较,以确认您正在与期望的对象通信。
**setup:**这控制DTLS代理行为。这决定了在ICE连接之后,它是作为客户机还是服务器运行。可能取值为:

  • setup:active -作为DTLS客户端运行。
  • setup:passive -作为DTLS服务器运行。
  • setup:actpass -让其他WebRTC代理选择。
    **mid:**识别会话描述中的媒体流。
    ice-ufrag:这是ICE Agent的用户分片值。用于对ICE Traffic进行认证。
    ice-pwd:这是 ICE Agent的密码。用于对ICE Traffic进行认证。
    rtpmap:此值用于将特定的编解码器映射到RTP有效负载类型。有效负载类型不是静态的,因此对于每个调用,提供程序决定每个编解码器的有效负载类型。
    fmtp:为一个有效负载类型定义附加值。这对于传达特定的视频配置文件或编码器设置非常有用。
    **candidate:**这是一个来自ICE Agent的ICE Candidate。这是WebRTC Agent 可用的一个可能地址。这些将在下一章详细解释。
    ssrc :一个同步源(SSRC)定义了一个单一的媒体流轨迹。
    label:是这个单独流的ID。mslabel是容器的ID,容器里面其中可以有多个流。

WebRTC会话示例

下面是WebRTC客户端生成的完整会话描述:

v=0
o=- 3546004397921447048 1596742744 IN IP4 0.0.0.0
s=-
t=0 0
a=fingerprint:sha-256 0F:74:31:25:CB:A2:13:EC:28:6F:6D:2C:61:FF:5D:C2:BC:B9:DB:3D:98:14:8D:1A:BB:EA:33:0C:A4:60:A8:8E
a=group:BUNDLE 0 1
m=audio 9 UDP/TLS/RTP/SAVPF 111
c=IN IP4 0.0.0.0
a=setup:active
a=mid:0
a=ice-ufrag:CsxzEWmoKpJyscFj
a=ice-pwd:mktpbhgREmjEwUFSIJyPINPUhgDqJlSd
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:111 opus/48000/2
a=fmtp:111 minptime=10;useinbandfec=1
a=ssrc:350842737 cname:yvKPspsHcYcwGFTw
a=ssrc:350842737 msid:yvKPspsHcYcwGFTw DfQnKjQQuwceLFdV
a=ssrc:350842737 mslabel:yvKPspsHcYcwGFTw
a=ssrc:350842737 label:DfQnKjQQuwceLFdV
a=msid:yvKPspsHcYcwGFTw DfQnKjQQuwceLFdV
a=sendrecv
a=candidate:foundation 1 udp 2130706431 192.168.1.1 53165 typ host generation 0
a=candidate:foundation 2 udp 2130706431 192.168.1.1 53165 typ host generation 0
a=candidate:foundation 1 udp 1694498815 1.2.3.4 57336 typ srflx raddr 0.0.0.0 rport 57336 generation 0
a=candidate:foundation 2 udp 1694498815 1.2.3.4 57336 typ srflx raddr 0.0.0.0 rport 57336 generation 0
a=end-of-candidates
m=video 9 UDP/TLS/RTP/SAVPF 96
c=IN IP4 0.0.0.0
a=setup:active
a=mid:1
a=ice-ufrag:CsxzEWmoKpJyscFj
a=ice-pwd:mktpbhgREmjEwUFSIJyPINPUhgDqJlSd
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 VP8/90000
a=ssrc:2180035812 cname:XHbOTNRFnLtesHwJ
a=ssrc:2180035812 msid:XHbOTNRFnLtesHwJ JgtwEhBWNEiOnhuW
a=ssrc:2180035812 mslabel:XHbOTNRFnLtesHwJ
a=ssrc:2180035812 label:JgtwEhBWNEiOnhuW
a=msid:XHbOTNRFnLtesHwJ JgtwEhBWNEiOnhuW
a=sendrecv

以下是我们从这条信息中了解到的:
我们有两个媒体部分,一个音频部分和一个视频部分。
它们都是sendrecv收发器。我们得到了两个流,我们可以发送两个回去。
我们有ICE候选人和身份验证详细信息,因此我们可以尝试连接。
我们有一个证书指纹,所以我们可以进行安全通话。

Connecting

为什么WebRTC需要一个专用的子系统来连接?

目前部署的大多数应用程序都建立 client/server连接。但是客户端/服务器连接要求服务器有一个稳定的公开的传输地址。客户端与服务器连接,服务器随后响应。

WebRTC不用 client/server 模型,它用点对点(P2P)连接。在P2P连接中,创建连接的任务平均分配给两端。这是因为WebRTC中的传输地址(IP和端口)不能被假定,甚至可能在会话期间发生变化。WebRTC将尽可能地收集所有信息,并将竭尽全力实现两个WebRTC Agent之间的双向通信。

不过,建立点对点连接可能很困难。这些Agent可能位于不能直连的不同网络中。在存在直连的情况下,可能遇到其他问题。比如说,客户端不使用相同的网络协议(UDP <-> TCP)或可能使用不同的IP版本(IPv4 <-> IPv6)

尽管在建立P2P连接时存在这些困难,但由于WebRTC提供的以下属性,您获得了优于传统客户端/服务器技术的优势。

  1. 降低带宽成本
    因为媒体通信直接发生在对等点之间,你不需要付费,也不需要托管一个单独的服务器来转发媒体。
  2. 更低的延迟
    直连更快捷,当通过服务器运行所有内容时,传输速度会变慢
    3.Secure E2E Communication
    端到端安全通信:直接交流更安全。由于用户不会通过您的服务器路由数据,所以不用担心服务器会不会解密其数据

上面描述的过程称为交互式连接建立(ICE)。另一个早于WebRTC的协议。ICE是一种试图找到两个ICE代理之间通信的最佳方式的协议。每个ICE Agent都会公布如何访问自己,这些路径被称为candidates(候选地址)。candidates本质上是agent的传输地址,它认为另一个对端可能可以到达该传输地址。然后,ICE决定candidates的最佳组合。

现实世界的网络限制

ICE就是要克服现实世界网络的限制。在探讨解决方案之前,先谈谈实际问题

1. 不在同一个网络

在这里插入图片描述
对于同一网络中的主机来说,连接非常容易。192.168.0.1 ->192.168.0.2很容易做到。这两台主机可以在没有任何外部帮助的情况下就可以相互连接。
然而,使用路由器B(routerB)的主机没有办法直接访问路由器a(routerA)后面的任何主机,你如何区分路由器a(routerA)后面的192.168.0.1和路由器B(routerB)后面的相同IP ? 它们使用内网ip 。使用路由器B(routerB)的主机可以直接向路由器A(routerA)发送流量,但请求将在那里就结束。路由器A(routerA)如何知道它应该把消息转发给哪台主机?

2. 协议限制

一些网络根本不允许UDP流量,或者可能他们不允许TCP。一些网络MTU(最大传输单元)可能非常低。网络管理员可以改变很多变量,从而这些修改使通信变得困难。

3. 防火墙/IDS规则

另一个是“深度包检测”和其他智能过滤。一些网络管理员会软件,这些软件会试图处理每个数据包的。很多时候,这些软件无法识别 WebRTC 的数据包,由于它们不知道如何处理,它们可能会阻拦这些数据包,例如,它们可能将 WebRTC 数据包视为不在端口白名单上的可疑 UDP 数据包。

NAT 映射

NAT(网络地址转换)映射是让WebRTC的连通性成为可能。WebRTC使用NAT让出于不同子网中的两端通信,解决了上述“**不在同一个网络”**的问题。NAT 映射不使用中继,代理或服务器。虽然Agent 1和Agent 2他们在不同的网络中,但是是可以通信的。
在这里插入图片描述
为了实现这种通信,需要建立一个NAT映射。Agent 1通过7000端口与Agent 2建立WebRTC连接。这将创建192.168.0.1:7000到5.0.0.1:7000的绑定。这允许Agent 2通过发送到5.0.0.1:7000的报文到达Agent 1。这个示例中的NAT映射就像在路由器中进行端口转发的自动版本。

NAT映射的缺点是:映射的形式不止一种(例如静态端口转发),并且映射的实现方式在不同的网络中是不一样的。互联网服务提供商和硬件制造商可能以不同的方式实现NAT映射。在某些情况下,网络管理员甚至会禁用它。好消息是,NAT映射的所有行为都是可以理解和观察到的,因此ICE Agent 能够确认其创建了NAT映射和映射的属性。描述这些行为的文档是RFC 4787。

创建映射

创建映射是最简单的部分。当你发送一个包到你的网络之外的地址时,一个映射就被创建了。NAT映射由NAT分配一个临时的公网IP和端口。出站消息将被重写,其源地址由新的映射地址给出。如果有消息被成功发到映射地址,消息会被自动路由返回给 NAT 网络中创建这个映射地址的主机。说到映射相关的细节,这就开始变得复杂了。

映射创建的行为【需要看】

映射创建分为三个不同的类别:

  1. 端点无关的映射
    这种创建方式为 NAT 网络中的所有发送者只创建一个映射。如果你将两个数据包发送到两个不同的远程地址,这个 NAT 映射将被重用。两个远程主机将看到相同的源 IP 和端口。如果远程主机响应,它将被发送回相同的本地侦听器。
    这是最好的情况。要使得呼叫能够建立起来,至少一侧必须是这种类型。
  2. 地址相关的映射
    每次将数据包发送到新地址时,都会创建一个新的映射。如果你将两个数据包发送到不同的主机,则会创建两个映射。如果将两个数据包发送到同一远程主机,但目标端口不同,则不会创建新的映射。
  3. 地址和端口相关的映射
    如果远程 IP 或端口不同,则会创建一个新的映射。如果将两个数据包发送到同一远程主机,但目标端口不同,则将创建一个新的映射。

映射过滤行为

映射过滤是关于允许谁使用映射的规则。它们分为三个类似的类别:

  1. 端点无关的过滤
    任何人都可以使用该映射。你可以与其他多个 peer 共享该映射,他们都可以向该映射发送流量。
  2. 地址相关的过滤
    只有为其创建映射的主机才能使用该映射。如果你将数据包发送到主机 A,则它可以根据需要响应任意数量的数据包。如果主机 B 尝试将数据包发送到该映射,将被忽略。
  3. 地址和端口相关的过滤
    仅有创建映射的主机和端口可以使用该映射。如果你将数据包发送到主机 A:5000,则它可以根据需要响应任意数量的数据包。如果主机 A:5001 尝试将数据包发送到该映射,将被忽略。

映射刷新

通常的建议是,如果 5 分钟未使用映射,则应将其销毁。但这完全取决于 ISP 或硬件制造商。
NAT 映射的创建即是 NAT 网络中的主机发送数据时,路由器的处理方式;而过滤即是接收数据时,路由器的处理方式。映射的刷新即是路由器释放映射的处理方式。不同网络情况不同,因此某些特定的搭配会导致两个网络间无法建立 P2P 连接。在穿透相关的技术中,将不同的情况称为不同的锥形。

STUN

STUN(NAT 会话传输实用程序)是一种用来配合 NAT 使用的协议。这是 WebRTC(和 ICE)之前的另一项技术。它由RFC 8489定义,该文件还定义了 STUN 数据包结构。STUN 协议也在 ICE/TURN 中被使用。

STUN 很有用,因为它允许以编程方式创建 NAT 映射。在 STUN 之前,我们能够创建 NAT 映射,但是我们不知道映射的 IP 和端口是什么? 有了STUN就可以知道映射的端口和IP是什么了。 STUN 不仅使你能够创建映射,还可以让你获取映射的详细信息,你可以他人分享这些详细信息,然后他们便可以通过你刚刚创建的映射向你传回数据。

让我们从对 STUN 的基本描述开始。稍后,我们再将话题扩展到 TURN 和 ICE 的用法。现在,我们只打算描述请求 / 响应流程来创建映射。然后,我们将讨论如何获取该映射的详细信息以便与他人共享。当你在 ICE URLs 中有一个用于 WebRTC PeerConnection 的 stun服务器时,此过程就会发生。简而言之,STUN 向 NAT 外部的 STUN 服务器发送请求,服务器返回其在请求中观察到的内容,STUN 根据这些内容来帮助 NAT 后面的端点找出已创建的映射。

Protocol Structure

 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 消息类型
每个 STUN 数据包都有一个类型。目前,我们仅关心以下几种:

  • Binding Request - 0x0001
  • Binding Response - 0x0101
    为了创建一个 NAT 映射,我们发出一个 Binding Request。然后服务器回应一个 Binding Response

消息长度
这就是 Data 段的长度。这一段中包含由消息类型所定义的任意数据。

Magic Cookie
指的是固定值 0x2112A442,以网络字节顺序发送。这个值有助于将 STUN 流量与其他协议区分开。

交互(Transaction)ID
一个 96-bit 的标识符,用于唯一标识一个请求 / 响应对。这可以帮助你配对请求和响应。

数据
数据将包含一个 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)                ....
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

STUN Binding Request 不使用任何属性。这意味着一个STUN Binding Request仅包含 header。

STUN Binding Response 使用一个 XOR-MAPPED-ADDRESS (0x0020)。此属性包含一个 IP 和一个端口。这正是所创建的 NAT 映射的 IP 和端口

创建 NAT 映射

使用 STUN 创建 NAT 映射只需要发送一个请求。你向 STUN 服务器发送一个 STUN Binding Request。然后,STUN 服务器回应一个 STUN Binding Response。 该 STUN Binding Response 将包含映射地址。映射地址是 STUN 服务器看到你的方式,也是你的 NAT 映射。 如果你希望某人向你发送数据包,那么你应该共享该映射地址。

人们还会将映射地址称为公网 IP 或 Server Reflexive Candidate。

确定 NAT 类型

不幸的是,映射地址可能并非在所有情况下都可用。如果是地址相关的映射,则只有 STUN 服务器才能将流量发送回给你。如果你共享它,那么另一个 peer 尝试向该地址发送的消息将被丢弃。这使得该 peer 无法与别的 peer 交流。如果 STUN 服务器还可以为你将数据包转发给对端 peer,你可能会发现地址相关的映射问题实际上是可以解决的!这也就是下面将要说到的 TURN 解决方案。

RFC 5780定义了一种方法,可以运行一个测试来确定你的 NAT 类型。这很有用,因为你可能会提前知道是否可以进行直接连接。

TURN

在无法建立直接连接的情况下,RFC 8656中定义了 TURN(使用中继穿透 NAT)。当两端的 NAT 类型不兼容,或者双方使用不同协议时,就需要使用 TURN。TURN 也可以被用于保护隐私的目的。如果通过 TURN 运行所有通讯,客户的真实地址在对端是被隐藏的。

TURN 使用专用服务器。该服务器充当客户端的代理。客户端连接到 TURN 服务器并创建一个对应的Allocation。通过创建该 Allocation,客户端将获得一个临时 IP/ 端口 / 协议三元组,其他 peer 可以使用该 IP/ 端口 / 协议将数据发送给该客户端。这个新的监听地址被称为中继传输地址。你可将其视为转发地址并分享给他人,以便其他人可以通过 TURN 向你发送流量。对于每个将获得该中继传输地址的 peer,你必须为其创建一个新的 Permission,以允许它与你进行通信。

当你通过 TURN 发送出站流量时,它会通过中继传输地址发送。当远程 peer 获得该出站流量时,他们会看到数据来自 TURN 服务器。

TURN 生命周期

下面就是一个客户端创建 TURN allocation 时必须做的所有事情。对于其他 peer 而言,与使用 TURN 服务器的客户端进行通信和其他客户端没有任何区别,先获得 IP 和端口,然后像跟其他任何主机一样通信。

Allocations

Allocations 是 TURN 的核心。本质上,一个 allocation 就是一个 “TURN 会话 “。要创建一个 TURN allocation,你需要与 TURN Server Transport Address(服务器传输地址,通常在 3478 端口)进行通信。

创建 allocation 时,你需要提供 / 确定以下内容:

  • 用户名 / 密码 - 创建 TURN allocation 时需要身份验证。
  • Allocation 传输方式 - 服务器(中继传输地址)与 peer 之间的传输协议, 可以是 UDP 或 TCP。
  • 连续端口 - 你可以为多个 allocation 请求顺序排列的一系列端口,这点与 WebRTC 无关。
    如果请求成功,你将在 TURN 服务器上获得响应,在响应的数据部分,包含以下的 STUN 属性:
  • XOR-MAPPED-ADDRESS - TURN Client 的 Mapped Address。当有人将数据发送到中继传输地址时,数据将被转发到该地址。
  • RELAYED-ADDRESS - 这是你提供给其他客户端的地址。如果有人将数据包发送到该地址,数据包会被转发到 TURN 客户端。
  • LIFETIME - Allocation 被销毁的时间。你可以通过发送 Refresh 请求来延长这一时间。
    译注:上面两个地址很拗口,但实际上理解起来并不复杂。Mapped Address 是 Turn Client 的实际地址,也就是 Turn Server 收到数据包时的目标地址。而 Relayed Address 是 Turn Client 的名义地址,也就是其他 WebRTC Agent 要发送数据给这个 Turn Client 时,所使用的地址。

权限

在你为远程主机创建权限之前,远程主机是无法通过你的中继传输地址发送数据的。所谓创建权限,即是告知 TURN 服务器一个 " 可以用来发送入站流量 " 的 IP 和端口。

远程主机需要先为你提供 TURN 服务器上使用的 IP 和端口。这意味着它应该先向 TURN 服务器发送一个 STUN 绑定请求。 有时会发生这样一个常见的错误情况,即是远程主机发送 STUN 绑定请求到另外一台服务器,然后再要求 TURN 服务器为此 IP 创建权限。

对于上面那种错误情况,假设你要为一个使用地址相关的映射的 NAT 网络的主机创建权限,如果你从其他 TURN 服务器生成映射地址,则所有入站流量都将被丢弃。因为每次他们与其他主机通信时,它都会生成一个新的映射。如果未被刷新,权限将在 5 分钟后过期。

译注:对于这个常见的错误情况,实际指的是被连接的主机从 TURN 服务器以外的 STUN/TURN 服务器获取本机 IP,再告知发起连接的主机这样的情况。当被连接的主机使用地址相关的映射类型的 NAT 时,它获取的 IP 在当前的 TURN 服务器上是无效的。

SendIndication/ChannelData

这是 TURN 客户端将消息发送到远端 peer 时所使用的两个消息。

SendIndication 是一个自包含的消息。它包含你希望发送的数据,以及你希望发送的目标。如果你要向远端 peer 发送大量消息的话,这种方式很昂贵。因为如果要发送 1,000 条消息,目标 IP 地址就被重复了 1,000 次!

ChannelData 允许你发送数据,但不需要重复 IP 地址。你需要先创建一个具有 IP 和端口的通道(Channel)。然后使用 ChannelId 发送,IP 和端口将在服务器端被填充进去。如果你要发送大量消息,这是更好的选择。

刷新

Allocations 将自动销毁。要避免其过早销毁,TURN 客户端必须在创建 allocation 时指定的 LIFETIME 到来之前,及时刷新它们。

TURN 使用方法

TURN 有两种用法。通常情况下,一个 peer 会作为 “TURN 客户端 " 连接,而另一方则直接进行通信。在某些情况下,你可能在两侧都需要使用 TURN 服务。举例来说,当两个客户端都位于在禁用 UDP 的网络中时,只能通过 TCP 连接到各自的 TURN 服务器来建立连接。

下面这些图有助于说明 TURN 的用法。
单个 TURN Allocation 通信
在这里插入图片描述
双重 TURN Allocation 通信
在这里插入图片描述
译注:单个 TURN Allocation 的情况,指的是一个 TURN Client 和另一个可访问的 UDP Client 的通信。双重 TURN Allocation 的情况,指的是两个 TURN Client 之间通信。

ICE

ICE(交互式连接建立)是 WebRTC 连接两个 Agent 的方式。这也是一项 WebRTC 前就有的技术,在RFC 8445中定义。ICE 是用于建立连接的协议。它会确定两个 peer 之间所有可能的路由,然后确保你保持连接状态。

这些路由被称为 Candidate Pair(候选地址对),也就是本地地址和远程地址的配对。这就是 STUN 和 TURN 在 ICE 中发挥作用的地方。这些地址可以是你的本地 IP 地址,NAT 映射或中继传输地址。通信双方需要收集它们要使用的所有地址,交换这些地址,然后尝试连接

两个 ICE Agent 使用 ICE ping 数据包(正式名称为连通性检查)通信以建立连接。一旦建立连接后,他们就可以发送任何数据。感觉就像使用普通 socket 一样。连通性检查使用 STUN 协议。

创建 ICE Agent

ICE Agent 要么处于控制中,要么处于受控中。控制中的 Agent 是决定选择候选对的 Agent。通常来说,发送 offer 的 peer 是控制中的一方。(一个控制别人,一个被别人控制)

每一方都必须有一个用户片段和一个密码。必须先交换这两个值,接下来才能进行连接性检查
用户片段以纯文本形式发送,用于多个 ICE 会话的解复用(demux)。
密码用于生成 MESSAGE-INTEGRITY 属性。在每个 STUN 数据包的末尾,都有这个属性,该属性是使用密码作为密钥的整个数据包的哈希值。这用于验证数据包并确保它未被篡改。

对于 WebRTC,所有这些值都通过上一章中所述的会话描述进行分发。

候选地址收集

现在,我们需要收集所有可能联通的地址。这些地址被称为候选地址 (Candidate)。

主机
主机候选地址直接在本地接口上侦听。可以是 UDP 或 TCP 方式。

mDNS
mDNS 候选地址类似于主机候选地址,但是其 IP 地址是隐藏的。你不必给对方提供你的 IP 地址,只需要给他们提供一个 UUID 作为主机名。然后设置一个多播监听器,并在有人请求你发布的 UUID 时进行响应。

如果你与 Agent 位于同一网络中,则可以通过多播找到彼此。如果不在同一网络中,则将无法连接(除非网络管理员明确配置网络以允许多播数据包通过)。

这对于保护隐私很有用。以前,用户可以通过 WebRTC 使用主机候选地址(甚至无需尝试与你连接)来找出你的本地 IP 地址。而使用 mDNS 候选地址的话,他们只能获得随机的 UUID。

服务器自反(Server Reflextive)
服务器自反候选地址是通过对 STUN 服务器执行 STUN 绑定请求时生成的。

当你收到 STUN 绑定响应时,XOR-MAPPED-ADDRESS 就是你的服务器自反候选地址。

Peer 自反
Peer 自反候选地址是指,当你从你不知道的地址收到入站请求时,由于 ICE 是经过身份验证的协议,因此你知道这些传输是合法的,这只是意味着远端 Peer 是通过它也不知道的地址与你通信。

这通常会发生在这样的情况下,当主机候选地址与服务器自反候选地址进行通信时,由于你是在子网外部进行通信,因此创建了一个新的 NAT 映射。还记得我们说过的连通性检查实际上是 STUN 数据包吗?STUN 响应的格式自然允许 peer 报告 Peer 自反地址。

中继
中继候选地址是通过使用 TURN 服务器生成的。

在与 TURN 服务器进行初始握手之后,你将获得 RELAYED-ADDRESS,这就是你的中继候选地址。

连通性检查

现在我们知道了远程 Agent 的用户片段,密码和候选地址。我们可以尝试连接了。 候选地址可以相互配对。因此,如果每边有 3 个候选地址,那么现在就有 9 个候选地址对。

看起来像这样
在这里插入图片描述

候选地址选择

控制中的 Agent 和受控中的 Agent 都开始在每个候选地址对上发送流量数据。这样是必须的,因为如果一个 Agent 位于一个地址相关映射的网络中,这样会创建 Peer 自反候选地址。

每个收到流量数据的候选地址对,会被提升为有效候选地址对。接下来,控制中的 Agent 将指定一个有效候选地址对。这就是提名候选地址对。然后,控制中的 Agent 和受控中的 Agent 再尝试进行一轮双向通信。如果成功,则提名候选地址对将成为选定的候选地址对!它将被用于后面的会话中。

重新启动

如果选定的候选地址对由于任何原因停止工作(如:NAT 映射到期,TURN 服务器崩溃等),则 ICEAgent 将进入失败状态。此时可以重新启动两个 Agent,然后重新完整执行整个过程。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值