P2P连接原理简述

1,933 阅读8分钟

背景

在实现云真机操控的过程中,为了实现非USB模式下的连接,需要使用 点对点通信技术进行音视频数据传输及其他数据交互。点对点通信允许直接在两个设备之间建立通信连接,而无需通过中间服务器。 在实践的过程中我们选择了webrtc进行,本文是对webrtc实现底层 P2P连接的原理简述。

NAT

NAT 全称 Network Address Translation,即网络地址转换,NAT是用于在本地网络中使用私有地址,在连接互联网时转而使用全局IP地址的技术,NAT一开始是为了解决IPv4地址短缺而开发的技术,而现在也作为安全防护的一种技术。

NAT工作原理

NAT 设备位于私有网络和公用网络之间,以下是一个简单的工作方式示例:

  1. 内部主机发送数据包到外部网络时,数据包首先到达NAT设备。
  2. NAT 设备根据**配置规则,**将源IP地址和端口号 按规则进行转换
  3. NAT 设备将转换后的数据包发送到外部网络。
  4. 外部网络返回响应数据包时,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

image.png

受限圆锥形

  • 一旦内部地址 iAddr:iPort 映射到外部地址 eAddr:ePort ,所有发自 iAddr:iPort 的数据包都经由 eAddr:ePort 向外发送;
  • 但只有曾经接收到 iAddr:iPort 发送的数据包的外部主机 nAddr:any 发送的数据包,才能经由 eAddr:ePort 到达 iAddr:iPort 。(注意,这里的 any 指外部主机源端口不受限制。即受限圆锥型限制了可以发送数据包的外部主机的 IP,但没有限制外部主机的端口号。)

image.png

端口受限型

  • 端口受限圆锥型在受限圆锥型的基础上,加上了对外部主机的端口号限制,即只有曾经接收到 iAddr:iPort 发送的数据包的外部主机 nAddr:nPort 发送的数据包,才能经由 eAddr:ePort 到达 iAddr:iPort 。

image.png

对称型

对称型的场景比较复杂一些。我们将内部地址 iAddr:iPort 与外部主机 nAddr:nPort 的地址和端口号组成一个四元组 (iAddr, iPort, nAddr, nPort) ,对于四元组中的不同取值,NAT 都会对应分配一个外部地址 eAddr:ePort ;并且也只有曾经收到内部主机数据的对应的外部主机,才能够把数据包发回 image.png

穿透服务/协议

不同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 所示:

  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 。
  2. A 向 S 发送请求,获取 B 的地址(Request Connection to B);S 会同时把 A 的地址转发给 B(Forward A’s Endpoints to B)。然后 A 和 B 都开始尝试相互向对方发送数据包。
  3. 当 A 向 B 第一次发送数据包时(Send to B at)会在 NAT_A 中产生映射 (10.0.0.1:4321, 138.76.29.7:31000) ;此时 NAT_B 并没有 A 和 B 的映射记录,数据包仍然会被丢弃。
  4. 当 B 向 A 第一次发送数据包时(Send to A at)会在 NAT_B 中产生映射 (10.1.1.3:4321, 155.99.25.11:62000) ;因为之前 NAT_A 已经创建了 A 和 B 的映射,所以 B 请求成功。
  5. 当 A 向 B 第二次发送数据包时,因为 NAT_B 也有了 A 和 B 的映射记录,所以 A 也请求成功。于是打洞完成,A 和 B 可以直接建立点对点连接(Session A-B)。

真实的网络情况可能会更加复杂,比如需要在多层 NAT 之间打洞。以及目前业界习惯使用 UDP 协议进行打洞,而不是 TCP 协议。

ICE

ICE (Interactive Connectivity Establishment) 交互式连接建立协议框架 是一种集成式NAT穿透技术框架,这个框架能让交互双端找到对方,并基于双方的NAT类型 建立连接。大致流程如下:

  1. TCP直接连接时,通过HTTP端口或HTTPS端口
  2. UDP 直连时,使用 STUN (Session Traversal Utilities for NAT) 服务器做 地址转发
  3. 间接连接时,使用TURN (Traversal Using Relays around NAT) 服务器做流量中继。

ICE的交互流程中,探测双方的NAT类型是由专门的 STUN或TURN服务服完成的。

STUN/TURN 协议

STUNSession Traversal Utilities for NAT,NAT会话穿越应用程序)是一种网络协议,它允许位于NAT(或多重NAT)后的客户端找出自己的公网地址,查出自己位于哪种类型的NAT之后以及NAT为某一个本地端口所绑定的Internet端端口。这些信息被用来在两个同时处于NAT路由器之后的主机之间建立UDP通信。该协议由 RFC 5389 定义。

方案

STUN使用下列的算法(取自RFC 3489)来发现NAT中间件以及防火墙(firewalls):STUN_Algorithm3_zh_Hans.svg.png

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…