最近在研究P2P技术,奈何相关资料不多,自己琢磨了一下,分享一下学习P2P的一些原理, 以及如何打造一个P2P聊天应用。
这里指的P2P是指peer to peer, 点对点的技术, 每个客户端都是服务端,没有中心服务器,不是websocket针对某个connection推送消息。
技术要点
- udp协议
- 节点之间的建立,连接和广播
- 内网穿透,如何能让两个处在内网的节点,相互发现自己的存在,并且建立通信
原理
首先解决的是内网穿透的问题,常见的底层协议tcp,udp,他们各自有优缺点,简单说明一下。 tcp:需要处理粘包问题,双工流通道,是可靠的链接。 udp: 每次发送的都是数据包,没有粘包问题,但是连接不可靠,只能传输少量数据
更加详细的请Google
这里选择udp协议,简单一些。
再下来是内网穿透,先说结论: 两个处于不同内部网络的节点,永远无法发现他们之间的相互存在,你就算是想顺着网线过去打他都不行。
所有的内网穿透原理无外乎需要一个有公网ip的中介服务器,包括虚拟货币像比特币之类的,所以首先要有一个创世节点
在NodeJS中,创建udp服务也很简单
const dgram = require("dgram");
const udp = dgram.createSocket("udp4");
udp.bind(1090, callback)
把服务部署要公网,那么其他所有的节点都能访问,通过中转服务器,能够使得两个节点可以建立连接
我们是要建立这样的P2P网络
假如现在只有3个节点: 创世节点, B节点, C节点, 创世节点有公网IP
我用对话的形式,阐述他们建立链接的过程:
B节点: hey,创世节点,我要加入到P2P网络里面,告诉其他兄弟,我来了 创世节点: 兄弟们,刚刚有个叫做B的节点加入网络了,你们也去告诉其他节点 其他节点: 刚刚收到来自 "创世节点"的通知,有个fresh meet加入网络了,叫做 “B”
… 至此,所有人都知道了B节点加入了网络,里面记载着B节点的相关信息,包括IP地址,包括udp端口号
此时C节点也要加入网络,并且想要和B节点对话:
C节点: hey,创世节点,我要加入到P2P网络里面,并且我要和B对话 创世节点: 兄弟们,刚刚有个叫做B的节点加入网络了,你们也去告诉其他节点,顺便看看有没有B这个节点 其他节点: 刚刚收到来自 "创世节点"的通知,有个fresh meet加入网络了,叫做 “C”,你们也看看有没有B这个节点 其他节点2: 收到通知,听说一个叫做C的节点在找一个B节点,我这里有它的信息,ip是xxxx.xxxx.xxx.xxxx, 端口10086 B节点: 有个C的家伙(ip: xxxx.xxxx.xxxx.xxxx, 端口1000)要找我
到这里,B获取到了C的信息,包括IP和端口,C也拿到了B的信息.
于是,他们两个就可以建立通信。消息流: B <----> C. 中间不经过任何服务器
用一张图来形容:
总结
在设计中,每个节点的功能都是一样的。如果需要加入到网络中,不一定跟创世节点链接
假设已存在的节点: 创世节点,A、B、C节点,此时有个D节点想要加入到网络。
那么D节点不一定非得链接到创世节点,可以链接到A、B、C中的任意一个节点,然后该节点再广播给其他节点说"Hey, 有个新人叫做D的加入了网络"。
这样所有人都知道,有个叫做D的节点存在,你可以和它通信,同时D节点和会同步已存在的节点。这样D节点也知道了其他节点的存在了。
最后
基于这一原理,可以打造出一个P2P的聊天应用,没有中间商赚差价。
这只是一些基本原理,离实际应用还差很多,有很多坑,比如D节点退出网络之后,要广播 “D节点退出网络了,把这个节点注销了吧,这波没他",还有消息加密,通信的双向验证(A节点想要B节点通信,但是不需要B节点的同意)等等,坑太多,填不完
原计划是搭建这么一个网络,然后写个electron的聊天应用,但是精力有限,就这样了。代码(写的丑,轻拍)
文字功底有点差,表述不清楚,见谅,如文中有误,欢迎指正与交流。
年后正在找一份NodeJS的工作,坐标深圳,哪里能投递
录制了一张gif图作为demo,在终端进行p2p通信。
但是Gif太大,17M
假设已存在的节点: 创世节点,A、B、C节点,此时有个D节点想要加入到网络。
那么D节点不一定非得链接到创世节点,可以链接到A、B、C中的任意一个节点,然后该节点再广播给其他节点说"Hey, 有个新人叫做D的加入了网络"。
那如果A,B,C都是内网节点,说白了都需要通过创世节点进行打洞,通过创世节点中转才能通讯,假设还是D节点进来,是不是还通过创世节点打洞?按你的说法D不一定非链接到创世节点。那这个时候创世节点挂了,也不就是因为没人维护打洞导致整个p2p网络都挂了? 那如果节点多了,又如何选择性连接到就近节点,DHT表又是如何构建的呢?
来自酷炫的 CNodeMD
lz 很简单诠释 p2p,求有没有 p2p 详细讲解的书?
@zy445566 还有很多点没涉及到的,所以也是在学习之中。 创世节点可以有几个,就好像比特币的种子服务器,在代码写死了有固定几个DNS地址,帮助发现节点列表。 成功加入网络之后,就需要同步节点。同步节点完成之后,你才会知道哪个节点是离你最近的。这时候两个节点之间的通信就需要依赖两个节点各自的网络情况了。
深圳的node.js工作,我这边有哇。腾讯云深圳总部,cdn团队。 alsotang@gmail.com