P2P
标签(空格分隔): P2P 网络
结构
- 网络扫描
- 对等网络 peer to peer
- 集中式P2P网络:qq 这样,有中心服务器的,登录,状态连接由服务器负责,客户端之间的交互,由客户端直接通讯
- 非结构化P2P网络:代表是Gnutella
- 分布式非结构化P2P网络:没有中心服务器,采用洪泛式搜索(Flooding)和随机转发机制(TTL转发机制),每个节点功能相同,兼作服务器和客户机
- 分布式结构化P2P网络
原理
存在着一些中间件,如NAT和防火墙
大多数中间件实现了一种非对称的通讯模型,即内网中的主机可以初始化对外的链接,而外网的主机却不能初始化对内网的链接
来自B的TCP SYN握手请求到达NAT A的时候会被拒绝,因为对NAT A来说只有外出的链接才是允许的。
中间件为常见的NAPT,内网中的客户端没有单独的公网IP地址, 而是通过NAPT转换,和其他同一内网用户共享一个公网IP
外部对NAT公网IP和端口主动的链接或数据都会因内网未请求被丢弃掉
锥形NAT(Cone NAT)
客户端A建立了两个连续的对外会话,从相同的内部端点(10.0.0.1:1234)到两个不同的外部服务端S1和S2。Cone NAT只为两个会话映射了一个公网端点(155.99.25.11:62000), 确保客户端端口的“身份”在地址转换的时候保持不变。
穿透方法
中继
逆向链接
UDP打洞(UDP hole punching)
第一种场景代表了大多数情况,即两个需要直接链接的客户端处在两个不同的NAT 之后;
1
2
3
4
5
6
7
8
9
10
11
12Server S
18.181.0.31:1234
|
|
+----------------------+----------------------+
| |
NAT A NAT B
155.99.25.11:62000 138.76.29.7:31000
| |
| |
Client A Client B
10.0.0.1:1234 10.1.1.3:1234- A和B分别初始化了 与Server的UDP通信
- A开始给B的公网地址发送UDP数据的同时,给服务器S发送一个中继请求,要求B开始给A的公网地址发送UDP信息,这样二者就可以建立通信
- 一旦新的UDP会话在两个方向都打开之后,客户端A和客户端B就能直接通讯, 而无须再通过引导服务器S了
- 一旦一个的P2P链接建立,链接的双方都能反过来作为“引导服务器”来帮助其他中间件后的客户端进行打洞, 极大减少了服务器的负载
第二种场景是两个客户端在同一个NAT之后,但客户端自己并不需要知道。
优化方案是明显的:perr端传内网ip,服务端可以获取外网ip,两个都同时试。第三种,端点在多级NAT之后,没办法最优化。
实现参考
大体思路:A想要与B建立 通信链路,先给服务器发送punch命令以及给B发送数据,服务器接到命令后给B发送punch_requst信息以及A的端点信息,B收到之后向A发送数据打通通路,然 后A与B就可以进行P2P通信了
tcp打洞
如果我们要进行TCP打洞,通常需要重用本地的endpoint来发起新的TCP连接,这样才能将已经打开的NAT利用起来。具体来说,则是要设置socket的 SO_REUSEADDR或SO_REUSEPORT属性
TCP打洞的步骤如下:
- A 发送 SYN 到 B (出口地址,下同),从而创建NAT A的一组映射
- B 发送 SYN 到 A, 创建NAT B的一组映射
- 根据时序不同,两个SYN中有一个会被对方的NAT丢弃,另一个成功通过NAT
- 通过NAT的SYN报文被其中一方收到,即返回SYNACK, 完成握手
至此,TCP的打洞成功,获得一个不依赖于服务器的链接
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 jaytp@qq.com