WebRTC:连接建立过程的网络穿透

点对点连接建立的难点

对基于WebRTC的点对点信来说,第一步是建立连接。这个过程有点复杂,至少可能会遇到以下两个问题:

  1. 问题一:连接双方可能互相不知道对方的地址;

  2. 问题二:连接双方可能都位于私有网络当中,中间隔着NAT设备;

对于问题一,只要通过某种方式,让连接双方获取对方的地址(IP:PORT)即可,比如连接到公共的server来交换地址(非本文重点)。

问题二则稍微麻烦一些。对位于局域网中的设备来说,建立点对点连接至少会遇到3个问题:

  1. 连接双方可能位于同一个局域网,也可能位于不同的局域网;

  2. 连接双方不知道自己本身的公网地址;

  3. 连接双方内网地址、公网地址已知的情况下,不一定能够直接建立连接;

Client A <--> NAT A <--> NAT B <--> Client B

WebRTC的解决思路

点对点通信关键的一点,就是让双方直接建立连接。然而,在某些情况下,两台主机无法直接通信,此时,可以借助中间代理进行间接通信。这也是WebRTC所采用的思路。

直接通信:Client A <——————————————> Client B 间接通信:Client A <——————代理 ——————> Client B

因为NAT带来的网络穿透问题,不管是直接通信,还是间接通信,都不是简单的事情。WebRTC通过ICE框架来解决网络穿透的问题,并对应用开发者屏蔽了复杂的技术细节。

ICE (Interactive Connectivity Establishment) ,交互式连接建立,是一种NAT穿透的框架,它集成了多种NAT穿越技术,比如STUN、TURN。

STUN(Session Traversal Utilities for NAT)

STUN(Session Traversal Utilities for NAT),NAT会话遍历实用工具。名字有点拗口,主要用途如下:

  • 检测分配给主机的外网IP和端口;

  • 检测NAT类型;

  • 检测两台主机之间的网络连通性;

相关视频推荐:

LinuxC++音视频开发视频免费】FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发

【文章福利】:小编整理了一些相关的音视频开发学习资料(资料包括C/C++,Linux,FFmpeg  webRTC  rtmp  hls rtsp ffplay  srs 等),qun994289133免费分享,有需要的可以加群领取哦!~点击裙994289133加入领取资料

确认外网IP和端口

STUN是C/S架构,实现这点相对简单,跳过协议细节,流程大致如下:

  1. 主机向STUN Sever发起地址查询请求;

  2. 请求数据包穿过NAT到达STUN Server。

  3. STUN Server收到请求,获得请求的来源IP、端口;

  4. STUN Server发送响应,响应数据包里包含了上面的来源IP、端口;

  5. 响应穿过NAT到达终端,终端获得自己的外网IP、端口;

检测NAT类型

NAT主要分4种类型:Full Cone、Restricted Cone、Port Restricted Cone、Symmetric。

这4种NAT类型的主要差异,体现在对UDP数据包的处理上,以Full Cone、Restricted Cone为例:

  • Full Cone:全锥型,任意来自相同内网IP、端口(IP_A、PORT_A)的请求,都会被映射到相同的外网IP、端口(IP_B、PORT_B)。此外,任意外网主机可以通过向IP_B、PORT_B发送数据包,来向内部主机发送数据包;

  • Restricted Cone:受限锥形,跟全锥形类似,任意来自相同内网IP、端口(IP_A、PORT_A)的请求,都会被映射到相同的外网IP、端口(IP_B、PORT_B)。不同之处在于,假设外网主机的IP地址是X,只有当内网主机曾经给IP地址X发送过数据包,该外网主机才能给内网主机发送数据包;

如何检测NAT类型呢?

假设STUN Server有两对公网IP、端口(IP_1 + PORT_1、IP_2 + PORT_2),假设内网主机(IP_A、PORT_A)向STUN Server的IP_1、PORT_1发送数据,STUN Server通过IP_2、PORT_2向该内网主机发送数据,那么:

  • Full Cone:内网主机可以收到数据;

  • Restricted Cone:内网主机收不到数据;

另外两种NAT类型这里不做介绍,4种NAT类型结合起来判断比较复杂,但基本原理是一样的,感兴趣的同学可以参考RFC 3489。

连通性检测

连接双方获知自己的IP地址、端口(可能有多对,比如内网地址+内网端口、外网地址+外网端口)后,通过信令服务器告知对方。剩下的工作,就是连通性检测:

  1. 双方是否有可连接上的IP地址、端口对;

  2. 哪个IP地址、端口对的通信质量最好;

细节先不展开。

TURN(Traversal Using Relays around NAT)

TURN对STUN进行了扩展,主要增加了中继服务器。

在某些情况下,NAT背后的两台主机无法直接通信,这个时候可以借助中继服务器来实现间接通信。

假设通信的两台主机分别为A、B。确认各自IP地址&端口、NAT类型 的方式跟STUN一致,不同之处在于A、B后续的通信方式。

STUN:A <————————————> B TURN:A <——— Relay Server ————> B

完整机制比较复杂,因为可能涉及多点通信,但原理很简单,主要包含地址分配、数据转发。

  1. 地址分配:主机A向TURN Server发起地址分配请求,TURN Server收到请求后,给主机A分配端口X;

  2. 数据转发:主机B向TURN Server发送数据,端口为X,TURN Server收到数据后,将数据转发给主机A;

更多细节可参考 《6.1. Sending an Allocate Request》和 《10. Send and Data Methods》

写在后面

WebRTC的连接建立过程比较复杂,为方便讲解,本文跳过了信令的交换过程、具体网络穿透协议的细节等,建议感兴趣的同学进一步查看相关文档/规范,以便加深了解,比如:

  1. NAT 4种类型有什么区别?STUN如何检测NAT类型?

一般将nat类型可以分为四种:全锥形,受限锥形,端口受限锥形,对称形。之所以是叫锥,可以想象一下圆锥,一个圆集中映射到一个点,也就是本地ip端口映射到nat服务器上面的公网ip和端口,其他任何远端ip和端口的网络都可以连接进来,这种就是全锥形,如果只有接收过连接的远端ip才能反向连接到本地ip,那这种就是受限形,其实就是ip受限形,如果再进行限制,只有接受过连接的远端ip和端口才能反连到本地ip,那这种就叫端口受限形。一般来说,本地服务器发起一个连接到任何远端ip,它对应的nat的端口都是不变的,如果发到不同的远端ip,它对应的nat的端口也不一样(公网ip也就是出口ip肯定是不变的),那这种就是对称形了,不同的远端ip对应不同的nat端口,形成一个对应关系,这种nat类型是不太好进行穿透的。

添加图片注释,不超过 140 字(可选)

检测NAT类型:1. 首先本地程序发起一个udp连接到stun服务器,这个服务器你自己开发一个就行,stun接受的udp请求后,可以根据from记录下该请求的ip和端口,这个就是nat服务器是的出口ip了,然后根据这个ip和端口回复一条信息,把获取到的ip和端口作为信息回复回去,如果本地能接收到,说明网络是没有问题的,如果接收不了,说明block了。

这里获取到了出口ip后,可以和本地ip做对比,如果一样,那说明压根就没有nat了,可以直接bind一下,能绑定成功就说明没有nat。

2. 本地重新发起一个请求到另外的stun服务器,通过同样的方法获取到出口ip和端口,将该端口和第一次的出口端口对比,如果变了,说明是对称形。

3. 本地程序再发起一个请求给stun, stun服务器接收到该请求后,换一个出口ip给回复回去,如果本地能收到回复,说明是全锥形的,换了一个ip也能接收到请求。如果接收不到请求了,对于非nat模式,那说明本地可能存在防火墙,nat下那还得继续探测。

4. 本地发起一个请求到stun服务器,让stun换一个端口进行回复,如果本地能接收到,那说明是ip受限形,否则就是端口受限形。

至此,nat类型检测完成,这是udp通信下测试的结果,对于全锥形,需要使用tcp进行反连接探测,如果连接不上,可能服务器对tcp做了限制。如果能连接上,说明可以正常穿透使用,可以将nat改为0,注意,本地要有保活的措施,定期对外发起tcp连接,以获取公网ip和端口,反连就是对公网ip和端口重新发起连接的。

2.ICE的过程通常比较慢,如何加快连接建立的速度?

如有错漏,敬请指出。

猜你喜欢

转载自blog.csdn.net/m0_60259116/article/details/123432405