文章目录
- 简述
- SDP
- NAT
- NAT的分类
- 完全圆锥型
- 受限圆锥型
- 端口受限圆锥型
- 对称型
- ICE
- STUN
- TURN
- 总结
- 参考链接
简述
WebRTC通过整合现有的网络协议为设备提供了实时通信的能力,其底层由 C++ 开发,并通过标准化的 JavaScript API 和原生接口(如 C++ 和 Java)向开发者开放。往大了说,WebRTC 实现了一整套支持实时通信的协议和方法。往小了说,WebRTC作为工具为开发者提供了快速开发实时通信系统的一套API。
由于WebRTC具有实时通信的特点,所以其广泛应用于音视频通话、视频直播、电话会议等领域。
接下来我们将一步一步讲解两台身处异地的设备是如何建立双向连接的,在这个过程会遇到许多问题,我们一起看看WebRTC是如何利用现有协议去解决的。
SDP
在因特网中可以通过目标设备的IP+端口向其发送数据,所以想要实现两台设备间的通信就需要互相都知道对方的IP端口。那么如何在茫茫人海中找到她呢,此时可以引入一个中间服务器(信令服务器),想要通信的双方在这个服务器上注册自己并互相发送自己的IP端口等信息。此后双方都知道了对方的IP端口信息就可以实现双向通信。
除了IP和端口信息,通信的双方还需要知道更多,比如说要传递音视频信息,双方要保证一样的编解码方式才可以保证数据在传输后能正常显示。因此WebRTC采用SDP(会话描述协议)用来描绘需要交换的信息,SDP类似JSON/XML只是规定了一种格式,它能够简单明了的表达通信双方想要传达的基本信息,例如音视频编码、地址信息等。
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
以上是SDP的一个示例,可以发现每行都由单个字符开始后接“=”,我们称之为Key。SDP规定了固定的key,常用的如下:
- v - Version,版本,版本,应等于 0。
- o - Origin,源,包含一个唯一 ID,用于重新协商。
- s - Session Name,会话名称,应等于-。
- t - Timing,时间,应等于 0 0。
- m - Media Description(
m=<media> <port> <proto> <fmt> ...
),媒体描述。 - a - Attribute,属性,一个自由文本字段,这是 WebRTC 中最常见的行。
- c - Connection Data,连接数据,应等于
IN IP4 0.0.0.0
。
像我们如果想携带自身的IP端口信息就可以写在a=candidate
后,这里不做过多的叙述,相信大家也记不住,在遇到的时候再去查就好。
NAT
到这里似乎都一切顺利,然而事情并不简单。在真实的网络环境中,设备发送的数据都会经过网关转发,设备实际使用的是处于局域网中的内部IP,这是因为IPv4地址短缺导致的。设备到公网的流量,都需要经过内网IP到外网IP的转换,这就是NAT(网络地址转换)。这使得我们上面所讲的通信方式无法实现,因为对于设备而言它只知道自己的内网IP,并不知道自己的消息去到公网后的IP,所以无法将自己的IP通过信令服务器告知对方。接下来我们来看看NAT主要做了哪些工作,以此找到实时通信的突破口。
NAT通常作用于路由器,它实际维护了一张内部IP与外部IP的映射表,当设备向外部发送数据时,NAT首先会查询是否有此源地址的记录,如果没有就会为其分配一个端口并创建一条映射,此时数据包的源地址会修改为路由器IP+端口,目的地址不变。当目的地址回包时,路由器进行查表,转发到对应的内部设备
由此我们可以找到突破口,只要能想办法告知对方设备经过NAT转换后的公网IP,建立实时通信就有希望成功。
我们首先考虑最简单的情况,假设:数据经过NAT由x.x.x.x:1001
发送后,所有目的地址为x.x.x.x:1001
的回包均被NAT接受并转发到内部设备。
在这个前提条件下,双方建立连接的步骤如下:
- 引入中间服务器,服务器功能为返回请求者其公网IP
- 设备A与设备B向中间服务器发起请求,获取到自身的公网IP
- 设备A与设备B通过信令服务器交换各自信息
- 设备A向设备B发送数据,由于设备B已经和中间服务器建立了NAT映射,此时A的数据能通过NAT到达B
NAT的分类
真实的NAT并不会像我们假设的一样简单,不同类型的NAT对映射生成、数据接收有不同的方式。
完全圆锥型
对于内部所有通过同一IP端口发送的请求,均映射为相同的外部IP端口,并且任何外部主机均可以通过映射的外部IP端口向内部主机发送数据。也就是我们上面提到的最理想的状态,这种NAT也是安全性最低的。
受限圆锥型
对于内部所有通过同一IP端口发送的请求,均映射为相同的外部IP端口,并且只有内网主机之前已经向公网主机发送过数据,此公网主机才可以向内网主机发送数据。
端口受限圆锥型
对于内部所有通过同一IP端口发送的请求,均映射为相同的外部IP端口,并且在受限圆锥型的基础上,增加了对端口的限制
对称型
对称型NAT把同一内网地址和端口到相同地址和端口的所有请求,都映射为一个公网地址和端口。对于上面三种NAT,只要是同一个内网地址端口生成的都是同一个映射。但是对称型,哪怕是同一台内网主机只要请求的地址不同,就会生成不同的映射。
介绍完4种不同类型的NAT,我们可以发现外部主机和位于NAT之后的主机通信的难易程度是:
完全圆锥<受限圆锥型<端口受限圆锥型<对称型
对于圆锥形我们可以用以下步骤建立连接:
- 设备A、B分别向中间服务器注册自己的地址
- 设备A向中间服务器请求设备B的地址,同时中间服务器同步A的地址给B,此后AB开始尝试互相发送数据包
- 设备A向B第一次发送数据,由于此时B的NAT还没有映射,此时数据会被丢弃
- 设备B向A发送请求,此时因为A已经发送过到B的数据生成了NAT映射,所以B能顺利到达A
- 设备A第二次向B发送数据,此时由于映射已经建立,数据能正常到达B
对于对称型NAT,由于其不同的目的地址会生成不同的映射,这导致外部设备无法直接与其进行通信,此时需要借助数据中转服务器,这个在后文提到。
ICE
针对上述不同NET类型有不同的建立连接方式,WebRTC是如何处理的呢?我认为这里首先要介绍的就是ICE(交互式连接建立),ICE能够使用各种方法确认两个客户端之间所有可能连接的路由,这些路由被称为:候选地址对。ICE收集到所有路由后会根据算法进行排序,随后通知到设备,设备通过信令服务器交换地址对后进行连通性测试,直到2台设备成功建立连接。我们上诉所讲的中间服务器,实则就是ICE服务器。
候选地址对有多种,其中:
- 主机候选对:这就是主机的真实IP和端口,主机候选对可以让通信双方快速确认是否都处于同一个局域网并快速建立连接
- 反射候选对:通过STUN获取到的公网IP
- 中继候选对:由TURN服务提供的中转流量服务IP
STUN
STUN(NAT 会话穿越应用程序)是一种可以获取位于NAT之后IP,并判断NAT类型的协议。它是一种C/S架构,由客户端发起请求,STUN服务返回其所见的IP也就是设备的公网IP,同时通过STUN可以辨别设备所处的NAT类型。
以上流程图描述了STUN是如何判断当前NAT属于何种类型:
首先由左上角开始进行测试一,该请求由客户端(设备)发起的普通STUN绑定请求,此时设备如果无法收到回复,说明设备处于的网络禁止了STUN服务,可能整个UDP协议均被禁用。如果设备正常收到了回复,此时可以根据回复中包含的IP地址这里称为:映射地址,来确定一件事,如果映射地址和设备地址相同,说明设备不在NAT之后。
如果设备不在NAT之后,此时进行第二次测试,客户端再次发起请求,但是此时请求需要带上CHANGE-REQUEST
改变IP和改变端口标记,这样STUN收到后就会通过不同的映射地址回复请求。此时如果设备收到了回复,说明设备暴露在公网,如果设备收不到回复,说明设备启动了对称型防火墙。
以上UDP被禁用、设备开启对成型防火墙都会导致P2P穿透失败
再次回到测试一,如果设备在NAT之后,进行测试二,如果能收到测试二的回复,说明设备处于完全圆锥型NAT之后。如果收不到测试二的回复,说明设备还有其他可能
此时发起第三次请求,并且需要修改请求的目的地址,此时检查返回的映射地址,如果和最开始做的测试一返回的结果不一致,说明NAT生成了新的映射,也就是对称型NAT。如果返回相同的映射地址,那么还剩最后两种NAT未区分。
最后进行测试3,对发起的请求需要携带CHANGE-REQUEST
改变端口标记,此时STUN服务器的响应会修改端口,此时如果设备能收到响应,说明设备位于受限圆锥型NAT,如果收不到响应,说明设备位于端口受限圆锥型NAT
TURN
在特定的情景下,设备无法建立直接的通信,此时需要一台公网的服务器作为中继,对数据进行转发,这就是TURN(NAT 中继遍历程序)。这也是设备双方能建立连接的保底方案,对于ICE来说,TURN服务返回的地址通常优先级是最低的。
TURN的工作流程如上图所示:
- 设备向TURN服务发起请求,此时TURN能够知道设备的公网地址如图中为:192.0.2.1:7000
- 此时TURN会创建一个ALLOCATION用于记录中继地址信息,随后TRUN分配一个中继地址如图中:192.0.2.15:50000
- TURN将中继地址返回给设备,设备通过信令服务器告知其他设备,此后其余设备向192.0.2.15:50000发送的数据均会通过TURN转发到192.0.2.1:7000的设备
总结
以上就是WebRTC在建立连接中涉及到的协议介绍,WebRTC整合后的连接流程如下图所示:
- 通信双方在信令服务器上注册,随后设备生成
初步候选地址
,这个初步候选地址就是本地的内网地址,然后创建offer,并将初步SDP发送给远端。随后生成候选地址对仍然会继续进行,并不断的通过信令服务器发送给远端。这样做的好处是可以加速连接的建立,在初步sdp发送后就可以开始协商建立连接。 - 流程图中的ICE Server包括了STUN、TURN等服务的交互,这里做了简化。实际上,信令服务器和ICE服务器也可以部署在同一台服务器上。
- 当双方通过ICE建立连接后,即可开始互相发送数据
参考链接
- https://webrtcforthecurious.com/zh/docs/03-connecting/
- https://webrtc.mthli.com/connection/peer-connection/
- https://www.cnblogs.com/ssyfj/p/14798399.html