Webrtc从理论到实践三:角色

系列文章目录

Webrtc从理论到实践一:初识
Webrtc从理论到实践二: 架构


一、一对一通信架构图

图1.1  webrtc 一对一通信架构图

图1.1 webrtc一对一通信架构图


二、通信角色介绍

在正式讲解之前,我想先对Webrc针对不同人数的多人通信常用的架构做一个简单的介绍,主要有以下三种架构:

  1. Mesh架构,每个端都与其他端互连,主要适用于五人以下的通信
  2. MCU(MultiPoint Control Unit)架构,每个浏览器只与中心的MCU服务器相连,MCU服务器负责所有的视频编解码,转码,混合等复杂逻辑,适用于50人以下且带宽有限的通信。
  3. SFU(Selective Forwarding Unit)模式,所有的客户端也是只与中心的服务器相连接,但是中心节点只负责转发,不做太复杂的处理,这样可以减轻中心服务器不小的压力。

我们这里主要讨论的是一对一的通信,所以采用P2P的架构比较合适.P2P连接的优势在于运营成本更低,没有流媒体服务器,最大的成本就是带宽,并且隐私性更好,服务提供商无权访问流媒体。但是它的缺点在于所需的上下行带宽和编解码时所需的CPU资源都过高,无法大规模扩展。

    从上图我们可以看到, 在架构图中主要存在四个角色:客户端1,中继服务器(STUN/TURN),信令服务器和客户端2。两个客户端在这里就不多做介绍了,主要介绍一下另外两个角色。

信令服务器

    首先说一下信令服务器,要实现Webrtc的一对一通信,信令服务器是最重要的一环。信令服务器的作用主要有三个:

  1. 具体业务信息的交换:如创建房间,加入房间,退出房间等;
  2. 网络相关信息交换:最常见的就是交换通信双方的IP和端口。
  3. 媒体相关信息交换:发送SDP描述信息,是否支持音频或者视频以及支持的编解码器信息。

中继服务器

    再来说一下中继服务器,中继服务器的主要目的就是为了实现P2P连接,这里的STUN 和TURN 分别代表了两种协议。
     这里说一下为什么要引入中继服务器才能实现P2P连接,这得从NAT的历史和原理说起。

NAT

    1993年提出的NAT(Network Address Translation,网络地址转换)技术是为了解决当时IPV4地址不足,而IPV6短期内还无法替换IPV4的问题,同时它还能够有效地避免来自外部网络的攻击。
     NAT的原理简单来讲,就是主机处于局域网中使用私有地址,当它想要与外部网络进行通信时,会将内部地址转换成公有地址,用这种方式,就可以只申请一个合法的IP地址就可以将一整个局域网的计算机接入互联网中,从而可以缓解共有IP地址紧缺的问题。举个例子:比如主机A在局域网中的地址是192.168.1.2 ,如果A想要与公网中的服务器B(地址是 202.20.65.4)通信,那么A发送的IP数据包在 经过网关的时候,就会把源IP地址改为一个对应的全局IP地址202.20.65.5,这样就可以完成通信。
NAT可以分为三种类型:
1.静态NAT,私有IP地址和公有IP地址是一对一不变的
2.动态NAT,通过共享NAT地址池来动态建立NAT映射关系。在内网主机需要进行NAT转换时需要从连接池中选择空闲的全局地址进行映射,每条映射记录时动态建立的,在连接时也会被收回。
3.网路地址端口转换,则是把内部地址映射到外部网络的一个IP地址不同端口上。这个是目前是用最普遍的一种方式,如果两台主机访问同一服务器的源端口不同时,在Track Table里加入端口信息区分既可,当两台主机访问同一台服务器的源端口正好相同时,则需要对源端口进行相应转换。下图可以清晰的表现出这种转换。 在这里插入图片描述

图2.3.1 网络地址端口转换流程图

然而由于 网关会将外部网络发起的主动连接直接丢弃,这就给P2P连接带来很大的麻烦。所以如果想让两个处于NAT后的终端直接通信,就需要一些适用于P2P网络的NAT穿越技术,比如反向链接技术,应用层网关ALG(Application Level Gateway)技术,打洞技术,中间件技术等。

STUN

    STUN(Session Traversal Utilities for NAT,NAT会话穿越应用程序)用于检测网络中是否存在NAT设备,并获取两个终端经NAT设备分配的外网IP地址和端口,然后建立一条可穿越NAT的P2P链接,这一过程也被形象的称为“打洞”。STUN无需现有的NAT设备做任何改动,只需要在组网中搭建一台STUN服务器,操作简便,所以得到广泛的应用。
    STUN采用C/S架构,由STUN服务器和STUN客户端组成,如下图所示
在这里插入图片描述

图2.4.1 STUN架构
在讲解STUN的工作原理之前,还有必要先讲清楚NAT的四种类型,从形态上可以分为锥型和对称型,因为锥型访问不同的外网主机时都共用同一个“洞”,形态上很像锥型,这也是其名字的由来,而对称型每次在访问新的主机时,都会重新打一个“洞”,可以见下图。然后锥型根据其对外部主机访问的限制又分为完全锥型,IP限制锥型和端口限制锥型。

在这里插入图片描述

图2.4.2 锥型形态

在这里插入图片描述

图2.4.3 对称型形态
  1. 完全锥型:一旦打洞成功,外部所有知道该洞的主机都可以与内网主机通信。比如当内网主机A(ipA:portA)与 外部主机B 通信时在NAT上打了一个洞,主机A映射到外网的地址是ipA2:portA2,那么外部主机C只要发送数据包给ipA2:portA2都能够与内网主机A进行通信。
  2. IP限制锥型:延用上面的例子,A与B进行通信,但是只有收到过A的数据包的才可以将数据包通过ipA2:portA2发给A,主机C就不可以与主机A通信,因为NAT映射表上会记录通信过的IP地址
  3. 端口限制锥型:端口限制型比IP限制型更为严格,除了会限制发送数据包的IP地址还会限制端口,比如A与B的端口portB1进行过通信,那么就只有ipB1:portB1可以与A通信,ipB1:portB2都不可以。
  4. 对称型:对称型是四种NAT中对数据包检测最严格的,内网主机每次访问不同的外网主机时,都会生成一个新的端口,不像锥形NAT会使用同一个洞,正是这种特性给NAT穿透造成了很大的麻烦,其映射的外网IP地址和外网端口都会随着访问不同的主机而变化,所以Webrtc碰到“对称型NAT遇到对称型NAT”或者“对称型NAT碰到端口限制型NAT”的情况,打洞成功率低,并且成本非常高,会直接放弃打洞的尝试。

STUN 进行内网穿透主要有两个阶段,一是探测阶段,二是打洞阶段,其中探测阶段比较重要,它又分为两个步骤,第一个是探测内网中是否存在NAT保护,第二个步骤是 判断NAT的类型。下面我将结合流程图为大家讲解一下这两个步骤。(注:以下流程是基于两台STUN服务器,每台STUN服务器具有两块网卡,每块网卡都配置公网IP地址的情况下进行的

NAT探测

在这里插入图片描述

图2.4.4 NAT探测流程
  1. 内网中主机1向服务器1发送一个STUN请求,服务器1以相同的IP和端口返回一个STUN响应。此时,主机1会启动一个定时器,规定时间内没有收到响应则探测结束,说明主机1与服务器之间的UDP不通
  2. 若规定时间内收到响应,响应包中记录着主机1的公网IP地址,此时主机1需要判断响应包中的IP地址与自己本地的IP地址是否一致。若不一致,则存在NAT保护,后续要进一步判断NAT类型
  3. 若一致,则主机1在公网上,需要进一步判断是否在防火墙之后,因为防火墙也会限制主机的数据发送与接收。主机1再次向服务器1发送请求,服务器1收到主机1的第二次请求,这次需要使用第二块网卡来返回响应信息。如果主机1可以收到服务器1的响应,则说明它是一台没有任何防护的公网主机,否则说明有对称性防火墙保护。
NAT类型探测

在这里插入图片描述

图2.4.5 NAT类型探测流程
  1. 当检测出具有NAT保护后,需要进一步判断NAT的类型。首先向服务器1发送STUN请求,服务器1收到请求后使用第二块网卡给主机1返回响应,如果在规定时间内收到响应则是完全锥型
  2. 否则,主机1需要向服务器2发送STUN请求,为了判断与服务器1通信得到的主机1外网IP地址和与服务器2通信得到的主机1外网IP地址是否一致,如果不一致,则是对称型
  3. 否则,主机1再次向服务器1发送STUN请求,服务器1收到请求后,使用接受消息的网卡和不同的端口向主机1返回响应消息,如果主机可以收到响应消息,则是IP限制型
  4. 否则是端口限制型
打洞阶段

这里所谓的”洞“就是在NAT上建立了一个内外网映射表,我们以最简单的完全锥型举例,这张表包括内网ip和内网port,映射的外网ip和外网port,格式如下
{
内网ip,
内网port,
映射的外网ip,
映射的外网port,
}

不同类型的NAT之间可能无法进行穿越,下表是各NAT是否可穿越表

NAT类型 NAT类型 是否可穿越
完全锥型 完全锥型
完全锥型 IP限制锥型
完全锥型 端口限制锥型
完全锥型 对称型
IP限制锥型 IP限制锥型
IP限制锥型 端口限制锥型
IP限制锥型 对称型
端口限制锥型 端口限制锥型
端口限制锥型 对称型
对称型 对称型
表2.4.1 各类型穿越可行表
IP限制型与对称型

下面我将以IP限制锥型和对称型之间的穿越过程为例,讲解Stun打洞的具体流程
在这里插入图片描述

图2.4.6 IP限制型与对称型穿越

第一、二步是主机先与STUN服务器通信,交换双方的外网的IP和端口等信息,然后在各自的NAT上创建映射表,比如

//A主机的NAT映射表
{
  A的内网IP,
  A的内网Port,
  A的外网IP,
  A的外网Port,
  [S的外网IP]
}
//B主机的NAT映射表
{
  B的内网IP,
  B的内网Port,
  B的外网IP,
  B的外网Port,
  S的外网IP,
  S的外网Port
}

之后就是第三步主机A向第一二步获得的主机B外网Ip和端口发送数据,但是此时主机B的NAT映射表中没有主机A的记录,所以主机A发往主机B的数据就会被丢弃,但是此时主机A的NAT映射表上增加了B的IP地址[S的外网IP,B的外网IP],最后进行第四步,因为主机B位于对称型NAT之后,所以每次访问一个新的IP主机时,会映射一个新的外网端口,并且重新打一个”洞“,生成的NAT表如下

//A主机更新后的NAT表映射
{
  A的内网IP,
  A的内网Port,
  A的外网IP,
  A的外网Port,
  [S的外网IP,B的外网IP]
}
//B主机新的NAT表映射
{
  B的内网IP,
  B的内网Port,
  B的外网IP,
  B的外网Port,
  A的外网IP,
  B的外网Port
}

此时,由于主机A上的洞已经生成,由于主机A位于IP限制锥型之后并且已经记录了主机B的外网IP,所以主机B向主机A的发送的数据可以正常到达主机A。同时,主机A也可以向主机B发送数据,至此IP限制锥型与对称型NAT打洞成功。

端口限制型和对称型

接下来,我想要解释一下为什么端口限制型无法与对称型进行NAT穿越。我们将上述图中的A主机放到端口限制型NAT之后。在第四步的时候由于B映射的外网端口如果是新的端口并且没有在A的NAT映射表中的记录该端口,所以数据包是无法发送到A主机的
在这里插入图片描述

图2.4.7 端口限制型与对称型穿越

TURN

前面说到了当遇到NAT无法打通的情况下,WebRtc就会使用TURN协议通过中转的方式来实现端到端的通信。下面,我将讲解一下TURN协议的通信流程。
TURN的全称是Traversal Using Relays around NAT,是STUN/RFC5389的一个拓展,建立在STUN上,消息格式使用STUN格式消息。主要添加了Relay中继功能。TURN和其他中继协议的不同之处在于,它允许客户端使用一个中继地址与多个不同的peer进行通信。TURN协议采用典型的客户端/服务器模式,其服务器端称为TurnServer,客户端称为TurnClient.。TurnServer和TurnClient之间通过信令控制数据流的发送。Turn协议工作原理,主要分为三个部分:分配(Allocation),转发(Relay)和信道(Channel)

分配

在这里插入图片描述

图2.5.1 申请relay地址

客户端首先向STUN Port(默认是3478端口)发送一个Allocate请求到服务器,服务器会给该客户端分配一个relay端口并且返回分配成功响应,在该response中包含了XOR-REPLAYED-ADREE属性,该属性的值是A的relay端口。该relay地址是个公网地址,相当于客户端A在公网上的一个代理,任何想要与A通信的客户端,只要将数据发送到A的relay地址就可以了。

转发机制

在这里插入图片描述

图2.5.2 转发机制流程

    任何想要与客户端A通信的人,只要知道客户端A的relay地址就可以,注意B在这里不是client,它被称为peer,client和peer之间有两种方式可以通过中继服务器交换数据,一种是relay,第二种是channel。client是可以同时与多个peer进行通信的,那么server是如何得知哪个peer应该接收数据,以及告知client接收的数据来自哪个peer的呢?
    转发机制,使用Send指令来把数据从client发送到server,使用Data指令来把数据从server发送到client.当使用Send指令时,client会发送一个Send Indication到服务器,包括以下内容

  1. XOR_PEER_ADDRESS属性:指定peer的地址(NAT映射后的外网地址
  2. DATA属性:包含要传给peer的数据
    当服务器收到Send Indication之后,会把DATA中的数据解析出来,然后再封装数据包的时候将源地址替换为client的relay地址,最后以UDP的格式发送到对等端。同样的,服务端收到来自peer的裸UDP数据,会将其封装成Data Indication,并添加XOR_PEER_ADRESS属性指明数据包来自哪个peer,然后发送给client。
    在这里插入图片描述
图2.5.3 数据包变化过程

如上图所示是B主动给A发消息:“Hello”,A回应“Hi”的过程。
a) 序号1、2、3、4、5为B的发送请求(蓝色箭头方向);
b) 序号6、7、8、9、10为A的回应,原路返回(绿色箭头方向)。
c) 1、2阶段时,发送的是裸的UDP数据。
d) 第3阶段是:从A的relay端口收到数据,添加STUN头后,最后从STUN Port 发出的过程
e) 在4、5过程中,是被STUN协议包装过的“Hello”,称之为Data indication。为了能够让客户端A知道这个包是哪个客户端发来的,所以,STUN 协议对“Hello”进行了重新的包装,最主要的就是添加了一个XOR-PEER-ADDRESS属性。
f) 6、7阶段为被STUN协议包装过的“Hi”,称之为Send indication。为了能够让A的relay port知道最终发往哪个客户端,因此也为“Hi”添加了STUN头,也是添加了XOR-PEER-ADDRESS属性。
g) 第8阶段是:从STUN Port 接收到带STUN 头的数据,去掉STUN头,最后从A的relay端口发出的过程。
h) 9、10是裸的UDP数据。

信道机制

    音视频数据转发场景中,使用Send/Data Indication转发机制,会多加的36字节格式信息,加重客户端和服务端之间的带宽压力。为改善这种情况,turn提供channeldata message信道机制。channeldata message不使用stun头部,而使用一个4字节的头部,包含一个称为信道号*的值(channel number)每一个使用中的信道号都与一个特定的peer绑定,即作为对等端地址的一个记号。要将一个信道与对等端绑定,客户端首先发送一个信道绑定请求(channelbind request)到服务器,并且指定一个未绑定的信道号以及对等端的地址信息。绑定后client和server都能通过channeldata message来发送和转发数据。信道绑定默认持续10分钟,并且可以通过重新发送channelbind request来刷新持续时间。和Allocation不同的是,并没有直接删除绑定的方法,只能等待其超时自动失效。

在这里插入图片描述

图2.5.3 信道机制流程

上图中0x4001为信道号,即channeldata message的头部中头2字节,值得一提的是信道号的选取有如下要求:
0x0000-0x3FFF :这一段的值不能用来作为信道号
0x4000-0x7FFF :这一段是可以作为信道号的值,一共有16383种不同值在目前来看是足够用的
0x8000-0xFFFF :这一段是保留值,留给以后使用.

下一篇 : 《Webrtc从理论到实践四:通信》

猜你喜欢

转载自blog.csdn.net/qq_39304481/article/details/125607072