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

1,150 阅读5分钟

点对点连接建立的难点

对基于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类型;
  • 检测两台主机之间的网络连通性;

确认外网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类型?
  2. ICE的过程通常比较慢,如何加快连接建立的速度?

如有错漏,敬请指出。

相关链接

Session Traversal Utilities for NAT (STUN)

Traversal Using Relays around NAT (TURN)