最近在研究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的聊天应用,但是精力有限,就这样了。代码(写的丑,轻拍)
文字功底有点差,表述不清楚,见谅,如文中有误,欢迎指正与交流。
大牛们的评论:朕有话说
还没有人评论哦,赶紧抢沙发!