P2P打洞过程详解

2022/1/29 23:10:08

本文主要是介绍P2P打洞过程详解,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

  • 什么是NAT。

NAT(Network Address Translation),网络地址转换协议。NAT是1994年提出的,当在专用网内部的一些主机本来已经分配到了本地IP地址(即仅在本专用网内使用的专用地址),但现在又想和因特网上的主机通信时,就可以使用NAT技术。

比如说内网ip地址192.168.1.155与外网ip地址150.158.106.96是无法直接通信,如果想要让这两个ip能够直接通信,就需要用到NAT技术将ip地址192.168.1.155先转换成公网ip地址和端口之后就可以进行通信了。

NAT的出现主要是因为IP4地址耗尽,理论上当全球IP6全面普及使用之后,NAT是可以退出历史舞台的。可见NAT的本质就是让一群机器公用同一个IP,这样就暂时解决了IP短缺的问题。

NAT的出现还有一个出于网络安全的原因,外网的主机要想攻击内网的主机,必须要经过防火墙,经过NAT转换才能找到内网的主机。

  • 路由器种类
  1. 基本型(没用)

当一个内网设备要访问外网时,路由器为这个内网ip分配一个外网ip完全供这个设备使用,通常需要路由器有多个外网ip。

  1. 对称型(无法穿透)

当一个内网设备要访问外网时,根据源地址,源端口,目的地址,目的端口的不同映射成外网ip下不同的端口进行会话。所以只要(源地址,源端口,目的地址,目的端口)其中的一个不同,会话的端口就会改变,所以无法穿透。

  1. 完全克隆型(最容易穿透)

当一个内网设备要访问外网时,根据源地址,源端口的不同映射成外网ip下不同的端口进行会话。

  1. 端口限制克隆型(可以穿透)

当一个内网设备要访问外网时,根据源地址,源端口的不同映射成外网ip下不同的端口进行会话。但路由器只接受目的端口返回的udp数据。

  1. 端口地址限制克隆型(可以穿透)

当一个内网设备要访问外网时,根据源地址,源端口的不同映射成外网ip下不同的端口进行会话。但路由器只接受目的端口且目的ip返回的udp数据。

以上3,4,5类路由器只要源地址和源端口相同,无论访问外网哪一个地址,映射成的端口都相同,这是这3种类型能穿墙的原因。

  • 如何判断是哪一种网络。

通过使用STUN服务器检测设备所处网络的NAT类型,STUN服务器需要两个公网IP。

我们假定client是要检测的设备,server是STUN服务器,并假设server的两公网SOCKET的IP地址和端口号分别是IP1:port和IP2:port。

步骤1:

client向server IP1:port发送请求,server使用IP1:port将收到请求的源IP和port(即设备的公网IP地址和端口号)回复给client,如果得到的公网IP和设备自身的IP一样,则判定设备自身处在公网,无NAT,检测结束,否则进行下一步。

步骤2:

client向server IP1:port发送请求,server使用IP2:port来回复,如果设备能收到回复,则判定client的NAT为完全锥形(Full Cone NAT),检测结束,否则进行下一步。

步骤3:

client向server IP2:port发送请求,server使用IP2:port将收到的源IP和port回复给client,client判断此port和步骤1得到的port是否一样,如果不一样,则为对称型(Symmetric NAT),检测结束;

如果一样,则为限制型(Restricted Cone NAT),这时候需要进一步检查是地址限制型NAT还是端口限制型NAT。

步骤4:

client向server IP2:port发送请求,要求server使用该IP的另一个端口来回复,server使用IP2:port2回复请求,如果client能收到回复,则判断为地址限制型(Address Restricted Cone) NAT,否则为端口限制型(Port Restricted Cone) NAT

  • udp打洞过程
  1. 网络拓扑图

外S1,外S2为假设在外部的两个辅助穿墙的server

PC1为子网1下想要连接PS1的client

PS1,为子网2下的,提供数据的server

  1. 打洞流程
  1. PS1 用udp向 外S1,S2 发送 注册登记请求,请求登记成功之后,外S1,S2

持有了PS1用于注册的名称(假设为“manager”)、外部的IP、外部的port、以及server

分配给PS1的session(由于udp不是长链接,所以,需要一个session区分对端是否断线重连)。由S1,S2持续向PS1发送心跳保活。

  1. 接着PC1 在 外S1上注册登记(假设为”client”)
  2. PC1创建两个子socket,一个用于send,一个用于recv,在S1上登记两个子sock,此时,

S1上有PC1 的三个外网ip+port,一个用于通讯,另外两个用于和PS1打洞

  1. PC1 请求 S1向 manager 发送 连接请求 (附带了client的session,client的两个sock外网ip+port)

  1. PS1 收到 S1 来的连接请求之后,创建两个sock,一个用于发送,一个用于接收,并通过S1发给PC1,并向PC1,的两个端口发送心跳包(第一次打洞,由于PC1从来没有给PS1发过数据,这些心跳包可能PC1收不到),

  1. PC1收到S1传来的PS1的两个端口之后,也向PS1发送心跳(第二次打洞,如果打洞成功,此时PS1应该能收到数据)

  1. PS1 检测到 PC1有发过来的数据,回两个心跳,并callback给其他逻辑(server端建立完成)
  2. PC1只要收到了PS1发过来的任何数据,直接返回connect连接成功,如果超时,则打洞失败,
  3. PC1 注销在S1的登记

PS:整个逻辑下来,PS1 和 PC1的socket中可能残存有未处理的心跳包(用于打洞用的数据)p



这篇关于P2P打洞过程详解的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程