目录

  • ​​概念与背景​​
  • ​​p2p​​
  • ​​为什么要nat穿越​​
  • ​​什么是nat打洞​​
  • ​​基于UDP协议的P2P打洞​​
  • ​​原理​​
  • ​​集中服务器​​
  • ​​P2P的Session建立原理​​
  • ​​P2P情景1: 两客户端位于同一NAT设备后面(即相同内网中)​​
  • ​​P2P情景2: 两客户端位于不同的NAT设备后面(分属不同的内网)​​
  • ​​P2P情景3: 两客户端位于两层(或多层)NAT设备之后(分属不同的内网)​​
  • ​​基于TCP协议的P2P打洞技术​​
  • ​​参考​​

概念与背景

p2p

P2P(peer to peer)即点对点通信,或称为对等联网,与传统的服务器客户端模式有着明显的区别,在即时通讯方案中应用广泛(比如IM应用中的实时音视频通信、实时文件传输甚至文字聊天等)。

P2P可以是一种通信模式、一种逻辑网络模型、一种技术、甚至一种理念。在P2P网络,所有通信节点的地位都是对等的,每个节点都扮演着客户机和服务器双重角色,节点之间通过直接通信实现文件信息、处理器运算能力、存储空间等资源的共享。

P2P网络具有分散性、可扩展性、健壮性等特点,这使得P2P技术在信息共享、即时通讯、协同工作、分布式计算、网络存储等领域都有广阔的应用。

  • 经典的CS模式
  • P2P之NAT打洞_客户端

  • P2P结构模型
  • P2P之NAT打洞_NAT_02

为什么要nat穿越

NAT技术和P2P技术作为经典的两项网络技术,在现在的网络上有着广泛的应用,P2P主机位于NAT网关后面的情况屡见不鲜。NAT技术虽然在一定程度上解决了IPv4地址短缺的问题,在构建防火墙、保证网络安全方面都发挥了一定的作用,却破坏了端到端的网络通信。NAT阻碍主机进行P2P通信的主要原因是NAT不允许外网主机主动访问内网主机,但是P2P技术却要求通信双方都能主动发起访问,所以要在NAT网络环境中进行有效的P2P通信,就必须采用新的解决方案。

即:此中的nat指的是Snat,允许内网主动访问外网;但是不允许外网主动访问内网。

为了兼容NAT,基于P2P的应用程序在开发的时候大多会根据自身特点加入一些穿越NAT的功能以解决上述问题。

P2P之NAT打洞_nat_03


NAT A 网下的设备 1(192.168.1.101)想与某公网 IP (42.120.241.46) 通讯,设备 1 将包发给 NAT A,然后 NAT A 对源 IP 进行转换发给 NAT B(中间可能还会经过多重 NAT)。这样做的目的是,NAT B 并不知晓 NAT A 下的各个设备,他只能与 NAT A 本身通讯,因此发送给 NAT B 的包源 IP 必须是 NAT A 的公网 IP,不然 NAT B 没有办法进行回复。

接下来 NAT B 将回复包再发回 NAT A,此时就是 NAT 发挥作用的时候了,NAT A 现在要做的就是将包再分发回之前的设备,如何确定要发给谁呢?NAT 中记录了一张表。之前 192.168.1.101 通过 2333 端口与 42.120.241.46 端口 443 通讯时,将 192.168.1.101:2333 转换为 123.122.53.20:60001;那么这次接受到发往该 NAT 123.122.53.20:60001的包时就应该转发给 192.168.1.101:2333。经过这样的过程,NAT A 下的设备都可以连接到互联网了!

如上图所示,由于 NAT 的存在,当 NAT A 的设备 1 想与 NAT B 下的设备通讯时,必然要将目标 IP 设置为 NAT B 的公网地址,而 NAT B 转发表中并没有记录过 NAT A 与自身网络下设备的通讯记录,因此没有转换记录,因此 NAT B 会将包丢掉。

什么是nat打洞

P2P 通信最大的障碍就是 NAT(网络地址转换),NAT 使得局域网内的设备也可以与公网进行通讯,但是不同 NAT 下的设备之间通讯将会变得很困难。UDP 打洞就是用来使得设备间绕过 NAT 进行通讯的一种技术。

P2P之NAT打洞_服务器_04

  • 公网中转服务器

为了能够进行 UDP 打洞,我们需要一台公网的服务器作为中转站,它是 NAT A 与 NAT B 之间的信使。

为了方便起见,我们把地址为 192.168.1.101 的设备称为设备 1,把地址为 192.168.1.2 的设备称为设备 2,信使服务器称为 S。

首先,设备 1 和设备 2 都向 S 注册自己,S 中能记录各个设备此时使用的公网 IP 地址和端口号,例如设备 1 是 123.122.53.20:31000,设备 2 是 42.120.241.46:41000。

然后设备 1 与设备 2 都向 S 获取对方的公网 IP 与之前预留的端口号,就像这样:

P2P之NAT打洞_NAT_05

  • 打洞

设备 1 向 42.120.241.46:41000 发一个包,NAT B 自然能接收到这个包,然而它不知道来自 NAT A 的包应该发给谁,因此 NAT B 将这个包舍弃。但是由于设备 1 向 42.120.241.46:41000 发过包,NAT A 会记录:以后来自 42.120.241.46:41000 的包都发给设备1。

设备 2 也做相同的操作,让 NAT B 也知道:以后来自 123.122.53.20:31000 的包都发给设备 2。至此,NAT A 与 NAT B 都互相为对方保留了端口,就可以愉快地通讯了。

基于UDP协议的P2P打洞

原理

UDP打洞技术是通过中间服务器的协助在各自的NAT网关上建立相关的表项,使P2P连接的双方发送的报文能够直接穿透对方的NAT网关,从而实现P2P客户端互连。

如果两台位于NAT设备后面的P2P客户端希望在自己的NAT网关上打个洞,那么他们需要一个协助者——集中服务器,并且还需要一种用于打洞的Session建立机制。

集中服务器

集中服务器本质上是一台被设置在公网上的服务器,作为中转站,建立P2P的两台内网的服务器都可以直接访问到这台服务器。位于NAT网关后面的客户端A和B都可以与一台已知的集中服务器建立连接,并通过这台集中服务器了解对方的信息并中转各自的信息。

同时集中服务器的另一个重要作用在于判断某个客户端是否在NAT网关之后。

具体的方法是:
一个客户端在集中服务器上登陆的时候,服务器记录下该客户端的两对地址二元组信息{IP地址:UDP端口}。

  • 一对是该客户端与集中服务器进行通信的自身的IP地址和端口号。
  • 另一对是集中服务器记录下的由服务器“观察”到的该客户端实际与自己通信所使用的IP地址和端口号。
    我们可以把前一对地址二元组看作是客户端的内网IP地址和端口号,把后一对地址二元组看作是客户端的内网IP地址和端口号经过NAT转换后的外网IP地址和端口号。
    集中服务器可以从客户端的登陆消息中得到该客户端的内网相关信息,还可以通过登陆消息的IP头和UDP头得到该客户端的外网相关信息。如果该客户端不是位于NAT设备后面,那么采用上述方法得到的两对地址二元组信息是完全相同的。

P2P的Session建立原理

假定客户端A要发起对客户端B的直接连接,具体的“打洞”过程如下:

  • 1)A最初不知道如何向客户端B发起连接,于是A向集中服务器发送消息,请求集中服务器帮助建立与客户端B的UDP连接。
  • 2)集中服务器将含有B的外网和内网的地址二元组发给A,同时,集中服务器将包含有A的外网和内网的地址二元组信息的消息也发给B。这样一来, A与B就都知道对方外网和内网的地址二元组信息了。
  • 3)当A收到由集中服务器发来的包含B的外网和内网的地址二元组信息后, A开始向B的外网和内网的地址二元组发送UDP数据包,并且A会自动锁定第一个给出响应的B的地址二元组。同理,当B收到由集中服务器发来的A的外网和内网地址二元组信息后,也会开始向A的外网和内网的地址二元组发送UDP数据包,并且自动锁定第一个得到A回应的地址二元组。由于A与B互相向对方发送UDP数据包的操作是异步的,所以A和B发送数据包的时间先后并没有时序要求。

P2P情景1: 两客户端位于同一NAT设备后面(即相同内网中)

P2P情景2: 两客户端位于不同的NAT设备后面(分属不同的内网)

P2P情景3: 两客户端位于两层(或多层)NAT设备之后(分属不同的内网)

基于TCP协议的P2P打洞技术

参考

https://zhuanlan.zhihu.com/p/40816201
http://www.52im.net/thread-542-1-1.html