背景
在实现云真机操控的过程中,为了实现非USB模式下的连接,需要使用 点对点通信技术进行音视频数据传输及其他数据交互。点对点通信允许直接在两个设备之间建立通信连接,而无需通过中间服务器。 在实践的过程中我们选择了webrtc进行,本文是对webrtc实现底层 P2P连接的原理简述。
NAT
NAT 全称 Network Address Translation,即网络地址转换,NAT是用于在本地网络中使用私有地址,在连接互联网时转而使用全局IP地址的技术,NAT一开始是为了解决IPv4地址短缺而开发的技术,而现在也作为安全防护的一种技术。
NAT工作原理
NAT 设备位于私有网络和公用网络之间,以下是一个简单的工作方式示例:
- 内部主机发送数据包到外部网络时,数据包首先到达NAT设备。
- NAT 设备根据**配置规则,**将源IP地址和端口号 按规则进行转换
- NAT 设备将转换后的数据包发送到外部网络。
- 外部网络返回响应数据包时,NAT 设备将目的 IP 地址和端口号进行逆转换,再将数据包发送回内部网络。
NAT 分类
要进一步理解NAT,首先就是了解NAT的分类。RFC2663把NAT分成了四类:传统NAT、双向NAT、两次NAT、多宿主NAT。由于最常见的就是传统NAT,这里只介绍传统NAT。 传统NAT还可以分成两类:基本NAT(Basic NAT)、NAPT(Network Address Port Translation,网络地址端口转换)。
基本NAT
基本NAT就是只针对IP地址的“重命名”。由于基本NAT并不考虑更高层的协议(如TCP、),所以它只是实现了一个内部IP地址到公网IP地址的一一对应。如果内部IP数量更少,那么每个内部地址都能被映射到一个共有公网IP。如果公网IP数量少于内部IP的话,就不能保证同一时间每个内部设备都能访问外网了(可能分配不到公网IP)。
静态 NAT
静态 NAT:一对一映射,将一个私有IP地址映射到一个公共IP地址。
动态 NAT
动态 NAT:动态分配公共IP地址给私有IP地址,使得多个私有IP地址可以共享少量公共IP地址。
NAPT
NAPT也被称为“一对多”的NAT,或者叫PAT(Port Address Translations,端口地址转换)、地址超载(address overloading)。上节讲述的 静态NAT 和 动态NAT 都可归类为 基础性NAT,它们仅将内网主机的私有IP地址 一对一地转换为公网地址,并不将 TCP/UDP 端口信息进行转换。而 NAPT 不但会改变经过这个NAT设备的IP数据包的IP地址,还会改变数据包的 TCP/UDP 端口号。
NAPT主要用于企业只有一个公网IP但是有多个业务系统需要被互联网访问的场景。NAPT普遍用于接入设备中,它可以将中小型的网络隐藏在一个合法的IP地址后面。。
NAPT的主要优势在于,能够使用一个全球有效IP地址获得通用性。主要缺点在于其通信仅限于TCP或UDP。当所有通信都采用TCP或UDP,NAPT允许一台内部计算机访问多台外部计算机,并允许多台内部主机访问同一台外部计算机,相互之间不会发生冲突。
NAPT类型
在NAPT模式下,在rfc3489中,根据数据包过滤限制的不同点 又可细分为几种不同的类型。
完全圆锥型
- 一旦内部地址 iAddr:iPort 映射到外部地址 eAddr:ePort ,所有发自 iAddr:iPort 的数据包都经由 eAddr:ePort 向外发送。
- 任意外部主机发送的数据包都能经由 eAddr:ePort 到达 iAddr:iPort
受限圆锥形
- 一旦内部地址 iAddr:iPort 映射到外部地址 eAddr:ePort ,所有发自 iAddr:iPort 的数据包都经由 eAddr:ePort 向外发送;
- 但只有曾经接收到 iAddr:iPort 发送的数据包的外部主机 nAddr:any 发送的数据包,才能经由 eAddr:ePort 到达 iAddr:iPort 。(注意,这里的 any 指外部主机源端口不受限制。即受限圆锥型限制了可以发送数据包的外部主机的 IP,但没有限制外部主机的端口号。)
端口受限型
- 端口受限圆锥型在受限圆锥型的基础上,加上了对外部主机的端口号限制,即只有曾经接收到 iAddr:iPort 发送的数据包的外部主机 nAddr:nPort 发送的数据包,才能经由 eAddr:ePort 到达 iAddr:iPort 。
对称型
对称型的场景比较复杂一些。我们将内部地址 iAddr:iPort 与外部主机 nAddr:nPort 的地址和端口号组成一个四元组 (iAddr, iPort, nAddr, nPort) ,对于四元组中的不同取值,NAT 都会对应分配一个外部地址 eAddr:ePort ;并且也只有曾经收到内部主机数据的对应的外部主机,才能够把数据包发回
穿透服务/协议
不同NAT之间的穿透性
NAT之间连接有十种组合类型
| 全锥型 | 全锥型 | 可打通 |
|---|---|---|
| 全锥型 | 受限锥型 | 可打通 |
| 全锥型 | 端口受限锥型 | 可打通 |
| 全锥型 | 对称型 | 可打通 |
| 受限锥型 | 受限锥型 | 可打通 |
| 受限锥型 | 端口受限锥型 | 可打通 |
| 受限锥型 | 对称型 | 可打通 |
| 端口受限锥型 | 端口受限锥型 | 可打通 |
| 端口受限锥型 | 对称型 | 无法打通 |
| 对称型 | 对称型 | 无法打通 |
打洞流程示例
以下演示了,双方都位于不同的NAT服务之下的打洞流程。示例来自于:bford.info/pub/net/p2p… 博文。
假设存在两台设备 A 和 B,它们分别位于各自的 NAT_A 和 NAT_B 之后。此时 A 第一次尝试和 B 建立点对点连接,向 NAT_B 发送数据包;然而 NAT_B 经过查表发现,之前并没有 A 和 B 的映射(即 A 的请求无法被转发到 B),于是来自 A 的数据包就会被丢弃。
为了能绕过 NAT 的限制,我们需要借助一台公网上的服务器 S 做地址转发。如下图 1 所示:
- A 与 S 建立连接(Session A-S),向 S 注册自己的内网地址 10.0.0.1:4321 ;S 会同时记录 A 在公网的地址 155.99.25.11:62000 。B 与 S 建立连接(Session B-S),向 S 注册自己的内网地址 10.1.1.3:4321 ;S 会同时记录 B 在公网的地址 138.76.29.7:31000 。
- A 向 S 发送请求,获取 B 的地址(Request Connection to B);S 会同时把 A 的地址转发给 B(Forward A’s Endpoints to B)。然后 A 和 B 都开始尝试相互向对方发送数据包。
- 当 A 向 B 第一次发送数据包时(Send to B at)会在 NAT_A 中产生映射 (10.0.0.1:4321, 138.76.29.7:31000) ;此时 NAT_B 并没有 A 和 B 的映射记录,数据包仍然会被丢弃。
- 当 B 向 A 第一次发送数据包时(Send to A at)会在 NAT_B 中产生映射 (10.1.1.3:4321, 155.99.25.11:62000) ;因为之前 NAT_A 已经创建了 A 和 B 的映射,所以 B 请求成功。
- 当 A 向 B 第二次发送数据包时,因为 NAT_B 也有了 A 和 B 的映射记录,所以 A 也请求成功。于是打洞完成,A 和 B 可以直接建立点对点连接(Session A-B)。
真实的网络情况可能会更加复杂,比如需要在多层 NAT 之间打洞。以及目前业界习惯使用 UDP 协议进行打洞,而不是 TCP 协议。
ICE
ICE (Interactive Connectivity Establishment) 交互式连接建立协议框架 是一种集成式NAT穿透技术框架,这个框架能让交互双端找到对方,并基于双方的NAT类型 建立连接。大致流程如下:
- TCP直接连接时,通过HTTP端口或HTTPS端口
- UDP 直连时,使用 STUN (Session Traversal Utilities for NAT) 服务器做 地址转发
- 间接连接时,使用TURN (Traversal Using Relays around NAT) 服务器做流量中继。
ICE的交互流程中,探测双方的NAT类型是由专门的 STUN或TURN服务服完成的。
STUN/TURN 协议
STUN(Session Traversal Utilities for NAT,NAT会话穿越应用程序)是一种网络协议,它允许位于NAT(或多重NAT)后的客户端找出自己的公网地址,查出自己位于哪种类型的NAT之后以及NAT为某一个本地端口所绑定的Internet端端口。这些信息被用来在两个同时处于NAT路由器之后的主机之间建立UDP通信。该协议由 RFC 5389 定义。
方案
STUN使用下列的算法(取自RFC 3489)来发现NAT中间件以及防火墙(firewalls):
TURN
TURN 服务是为了解决 对称型NAT 无法被穿越的问题, 此时需要使用 TURN服务来转发流量。
位于对称型 NAT 之后的客户端需要先在 TURN 服务器上创建连接,然后告诉所有对端设备发包到这个服务器上,然后服务器再把包转发给这个客户端。并且 TURN 服务器通常是和 STUN 服务器成对出现的,当 STUN 判断 NAT 为对称型时,就会交由 TURN 处理。
开源实现
在具体实践过程中,一般不需要我们自己实现穿透服务框架,而是直接使用开源技术,比如 coturn** **
参考资料 cloud.tencent.com/developer/a… webrtc.mthli.com/basic/p2p-h… bford.info/pub/net/p2p… blog.csdn.net/qd915149091…