开源大世界

kydsj.vip 【首页】

用户工具

站点工具


wiki:p2p通信技术

P2P通信


根据客户端的不同,客户端之间进行P2P传输的方法也略有不同,这里介绍了现有的穿越NAT进行P2P通信的几种技术。

2.1 中继(Relaying)


这种方法是实现P2P通信中最简单但效率最低的一种方式。它的工作原理是利用一个具有公网IP地址的服务节点作为中介,帮助两个处于内网的客户端进行数据的传输和中转。过程如下图所示:

                       服务器 S
                          |
                          |
   +----------------------+----------------------+
   |                                             |
 NAT A                                         NAT B
   |                                             |
   |                                             |
客户端 A                                      客户端 B

客户端A与客户端B不会直接进行数据交换,它们都与服务器S建立连接,通过S作为桥梁进行数据的中转。这种方式最大的缺点在于,随着连接客户端数量的增加,服务端的负载会急剧上升,这与P2P通信旨在减少中心服务器压力的优势相悖。然而,它也有显著的优点,即能够保证连接的可靠性,因此在多种应用场景中,它常被用作一种后备通信手段。

2.2 连接反向(Connection Reversal)


这是第二种P2P通信技术,适用于两个通信终端中至少有一个终端不处于任何中间件(NAT)之后的情形。比如,客户端A位于NAT后面,而客户端B具有一个全球唯一的IP地址,具体如下所示:

                            服务器 S
                        8.81.0.8:1235
                               |
                               |
        +----------------------+----------------------+
        |                                             |
      NAT A                                           |
155.99.25.11:62000                                    |
        |                                             |
        |                                             |
     客户端 A                                      客户端 B
  10.0.0.1:1234                               138.76.29.7:1234 

其中,客户端A的私有IP地址是10.0.0.1,并且它的应用程序使用TCP端口1234。它与服务器S建立连接,服务器S的IP地址是8.81.0.8,端口是1235。NAT A将公网IP地址155.99.25.11的TCP端口62000分配给了客户端A,这是客户端A当前会话的对外端口。因此,对服务器S来说,客户端A的地址是155.99.25.11:62000。由于客户端B有一个公网IP地址,对服务器S来说,其地址就是138.76.29.7:1234。

当客户端B尝试与客户端A建立P2P连接时,它可以尝试连接到A的公网地址155.99.25.11:62000,或者A的私网地址10.0.0.1:1234。不过,这两种尝试都会失败。连接到10.0.0.1:1234显然是不可能成功的,但为什么尝试155.99.25.11:62000也会失败呢?当来自客户端B的TCP SYN握手请求到达NAT A时,请求会被拒绝,因为NAT A只允许外发连接。当直接连接失败后,客户端B可以通过服务器S向客户端A发送一个连接请求,这样就能“反向”地从A端建立起客户端A与客户端B之间的点对点连接。

虽然当前许多P2P系统采用了这种技术,但它的局限性也很明显:只有当至少一方具有公网IP时,连接才能成功建立。随着越来越多的场景出现双方都位于NAT之后的情况,就需要采用我们接下来要介绍的第三种技术。

2.3 UDP打洞(UDP hole punching)


这是一种流行的P2P通信方法,称为“UDP打洞”,它依赖于防火墙和多数NAT设备的行为,这些设备允许通过合法的P2P程序在中间介质中开辟通路以建立直接的连接。这里主要介绍两种常见的情况和应用程序如何高效处理这些情况。第一种情况是两个客户端分别处于不同的NAT背后,这代表了大多数情形;第二种是两个客户端位于同一NAT背后,且这对客户端通常不会意识到这一点。

2.3.1. 不同NAT后的端点


考虑这样一种情形,客户端A和客户端B都位于不同NAT的内网之后。它们和服务器S运行的P2P应用都使用UDP端口1234,并且A和B都与服务器初始化了UDP通信。地址映射如下所示:

                            服务器 S
                        18.181.0.31:1234
                               |
                               |
        +----------------------+----------------------+
        |                                             |
      NAT A                                         NAT B
155.99.25.11:62000                            138.76.29.7:31000
        |                                             |
        |                                             |
     客户端 A                                      客户端 B
  10.0.0.1:1234                                 10.1.1.3:1234

假设客户端A打算与客户端B建立直接的UDP通信。如果A尝试直接向B的公网地址138.76.29.7:31000发送UDP数据,NAT B可能会忽略该数据,除非它是完全开放的NAT,因为该数据的来源地址和端口与最初只与服务器S建立的会话不匹配。同理,B向A发送数据也一样。

为了解决这个问题,A可以在尝试直接发送UDP数据给B的同时,请求服务器S告诉B开始向A的公网地址发送UDP数据。这样做会导致NAT A和NAT B分别为A到B和B到A的UDP流量开放新的通信会话。一旦双方都建立了新的UDP会话,客户端A和B就能够直接通信,而不必再通过服务器S。

UDP打洞技术的优势在于,一旦建立了P2P连接,连接双方都可以作为“中介服务器”辅助背后NAT的其他客户端进行打洞,从而大幅减少了服务器的压力。无论是否存在中间件,或者存在多少中间件,这种技术都能成功建立通信连接。

2.3.2. 相同NAT后的端点


现在让我们来看一种两个客户端A和B恰好在同一个NAT之后的情形,它们可能不知道自己位于同一个内网。A与服务器S建立了UDP会话,NAT分配了公网端口62000给A,同理,B与S建立的会话被分配了端口62001,如下图:

                          服务器 S
                      18.181.0.31:1234
                             |
                             |
                            NAT
                   A-S 155.99.25.11:62000
                   B-S 155.99.25.11:62001
                             |
      +----------------------+----------------------+
      |                                             |
   客户端 A                                      客户端 B
10.0.0.1:1234                                 10.1.1.3:1234

如果A和B采用之前描述的UDP打洞技术建立通信路径,会发生什么?首先,A和B会从服务器S处获知对方的公网IP和端口号,然后尝试向对方发送数据。他们只有在NAT允许内网到内网的UDP会话时才能成功通信,这被称为“回环传输”。例如,当A向B的公网地址发送UDP数据包时,数据包刚开始有源IP地址和端口号为10.0.0.1:1234,目的地址为155.99.25.11:62001;当NAT收到包后,把源地址转换为155.99.25.11:62000(A的公网地址),目的地址转换为10.1.1.3:1234后再发给B。即使NAT支持回环传输,这种转换和转发可能是不必要的,并可能会增加通信延迟并加重NAT的负担。

对这个情况的一个优化方案是,当A和B最初通过服务器S交换地址信息时,他们应该包括自己的内网IP地址和端口号(从自己的视角),以及服务器所观测到的他们的公网地址和端口号。然后客户端开始尝试通过对方已知的两个地址发送数据,首先使用成功通信的地址作为彼此的联系点。如果两个客户端在同一个 NAT后,发送到对方内网地址的数据最有可能先到达,从而可以建立一条不经过NAT的通信链路;如果两个客户端在不同的NAT之后,发送给对方内网地址的数据包 根本就到达不了对方,但仍然可以通过公网地址来建立通路。值得一提的是,虽然这些数据包通过某种方式验证,但是在不同NAT的情况下完全有可能会导致A往B 发送的信息发送到其他A内网网段中无关的结点上去的。

2.3.3. 多级NAT后的端点


当我们的网络由数层NAT设备构成时,建立最理想的点对点(P2P)连接变得复杂,特别是在没有关于网络拓扑结构详细信息的情况下。想象一下这样的网络设置:一个主服务器(服务器S),位于多个级联的NAT设备之上。每个NAT设备服务于一个子网,并分配唯一的公网IP地址给子网内的所有设备。在这种配置中,两个想要通信的对等节点(客户端A和客户端B)都藏在它们各自的NAT之后,如下所示:

                            服务器 S
                        18.181.0.31:1234
                               |
                               |
                             NAT X
                     A-S 155.99.25.11:62000
                     B-S 155.99.25.11:62001
                               |
                               |
        +----------------------+----------------------+
        |                                             |
      NAT A                                         NAT B
192.168.1.1:30000                             192.168.1.2:31000
        |                                             |
        |                                             |
     客户端 A                                      客户端 B
  10.0.0.1:1234                                 10.1.1.3:1234

NAT X可能是由ISP(互联网服务提供商)部署的工业级NAT,为下属的NAT A和NAT B共享一个公网地址。客户端A和客户端B,每个都位于这些子NAT的网络之内,需要通过NAT进行通信时要进行地址转换。

如果客户端A和B希望建立一个直接的P2P连接,他们可以通过服务器S来协调,但这不是最优的路径。直接发送信息到对方的内部NAT地址可能更理想,但遗憾的是,两端都不能确定对方的这些地址,因为服务器S只能看到公共IP地址155.99.25.11。即使它们知道了这些地址,也不能保证这些地址是可达的,因为可能会有地址冲突。

最终,他们只能依赖服务器S来进行UDP打洞,然后通过自己的NAT设备进行所谓的回环传输。

2.3.4. 固定端口绑定


UDP打洞技术依赖于一个条件:参与的NAT设备必须是Cone NAT类型或者类似的非NAT防火墙,这些设备能够维持内网IP和端口到公网IP和端口的固定映射。只要UDP端口处于活跃状态,映射就保持不变。如果像对称NAT那样,每个新的会话都分配新的公网端口,则UDP打洞就无法建立已经打通的通信链路。幸运的是,Cone NAT在今天被广泛使用,即使有一小部分对称NAT不支持这种打洞技术,UDP打洞还是一个广泛应用的解决方案。

相关

wiki/p2p通信技术.txt · 最后更改: 2024/04/28 10:18 由 math

⭐24小时内访问人数:【104】⭐