理论部分
首先,我们要明白p2p要如何实现
举个例子,

看这张图,就比如我有3快机器
1机器开放6001端口
2机器的34394端口链接着6001端口,并且2机器开着6002端口,
3机器的36460端口链接着6002端口,并且3机器开着6003端口
那么现在是如何记录的呢?
先看1机器,当有端口和1机器的端口相连时,node.js是可以获取到链接过来的机器的端口号的,而向1机器链接的这个34394端口,他是随机分配的.
所以我们可以知道:
1机器里存有2机器链接的端口号:
2机器存有1机器接受的端口号和3机器链接的端口号:
3机器存有2机器接受的端口号
那么,我们如何实现传输数据,我们可以从3机器通过存储的2机器接受的端口号发送给2机器,然后为了防止2机器发回来的数据又被接受,我们可以拒绝2机器返回的信息
然后同理,2机器通过接受到3机器发送的数据,遍历2机器自身存储的端口号,把消息传递给1机器,同时拒绝1机器的返回信息
这样我们就可以实现一个简单的p2p通信
话不多说直接代码
代码部分
直接发我的github上的内容,其中test3就是我自己使用的node.js实现p2p网络.
https://github.com/feige011/p2pnetwork
使用例子
开3个窗口先进入其test3.js的目录然后分别依次输入
HTTP_PORT=3001 FFF_PORT=6001 node test3.js
HTTP_PORT=3002 FFF_PORT=6002 node test3.js
HTTP_PORT=3003 FFF_PORT=6003 node test3.js
由于我的设计就是自动链接port小1的端口(为了操作方便),所以第一个输入他会告诉你链接失败,因为你没开6000端口,不用理他.后两个就可以成功链接,
然后在第3窗口打字,就会发现传输到2,1中
如果你在1窗口打字,发现2有内容出现是正常的,因为这个是我自己设计说拒绝他返回信息
然后就是我们的代码讲解
var express = require("express");
var WebSocket = require("ws");
var bodyParser = require('body-parser');
创建express路由和websocket的框架
至于第三个用来解析json数据的,我这里没用上,不过是为了你如果要通过post请求来进行配对链接的话,这个就有用了
var server_me;
var http_port = process.env.HTTP_PORT || 3002;
var p2p_port = process.env.FFF_PORT || 6002;
var sockets = [];
这个server_me是用来看要阻挡前一个端口发送数据的,他用来记录前一个端口是什么
http_post为了之后网络链接通过post请求等进行连接数据
p2p_port为了连接各个端口
这两个 process.env是从键盘输入,后面名字随便起的(没有FFF_PORT)
socket为了记录每一个窗口中存储的端口号,方便后面发送数据
var initHttpServer = () => {
var app = express();//创建express()实例
app.use(bodyParser.json());
process.stdin.setEncoding('utf-8');
process.stdin.on('readable',function () {
var chunk = process.stdin.read();
if(chunk!==null){
broadcast(chunk)
}
})
// app.get("/peers", (req, res) => {
// console.log("feifei map:"+sockets.length)
// res.send(sockets.map(s => s._socket.remoteAddress + ':' + s._socket.remotePort));
// });
// app.post("/addPeer", (req, res) => {
// connectToPeers([req.body.peer])
// res.send([req.body.peer])
// });
// app.get('/getNum', (req, res) => {
// res.send(num);
// })
// app.post('/numAdd', (req, res) => {
// num++;
// broadcast(responseLatestMsg());//广播
// console.log('block added:' + num);
// res.send();
// })
app.listen(http_port, () => console.log('listening http on port: ' + http_port));
}
process就是从键盘输入,就是输入内容,然后通过broadcast进行广播
为了操作方便,我直接就不用通过命令行输入什么链接端口了,要是需要通过命令大致就是我注销的那种写法
var initP2PServer = () => {
var server = new WebSocket.Server({port: p2p_port});
console.log(p2p_port-1);
server.on('connection', ws => {
console.log("feige!!!!!!!!!!is good");
initConnection(ws)
});
var s="ws://localhost:"+(p2p_port-1);
console.log(s);
var socket = new WebSocket(s);
server_me=socket
socket.on('open', () =>{
console.log("feige011 is back")
initConnection(socket)
} );
socket.on('error', () => {
console.log('connection failed');
})
console.log('listening websocket p2p port on:' + p2p_port);
}
这里主要先给自己端口开了
然后链接自己小1的端口
连接上的话就initConnection
然后还有给小1的端口记录到server_me中,好接下来阻挡他
var initConnection = (ws) => {//初始化链接
sockets.push(ws);
console.log("feifeifei:size="+sockets.length)
for(var i=0;i<sockets.length;i++){
console.log("feifeihaha:"+sockets[i]._socket.remoteAddress+":"+sockets[i]._socket.remotePort)
}
initMessageHandler(ws);
initErrorHandler(ws);
}
初始化链接,主要给连接的websocket存入自己的sockets列表中,
然后定理他的自己接受时要进行什么操作
var initMessageHandler=(ws)=>{
ws.on('message',(data)=>{
console.log("Received message"+data);
if(ws!==server_me){
console.log("fa song le shu ju")
broadcast(data);
// handleNum(data);
}else{
console.log("feifei**************"+sockets.length);
for(var i=0;i<sockets.length;i++){
console.log("feifei"+sockets[i]._socket.remoteAddress+":"+sockets[i]._socket.remotePort)
}
console.log("zu zhi le:"+ws._socket.remoteAddress+":"+ws._socket.remotePort)
console.log("feifei***********************");
}
})
}
当接受到数据时,如果不是阻挡的数据,就进行brocast广播,反之打印一下自己想看的东西
var initErrorHandler =(ws)=>{
var closeConnection =(ws)=>{
console.log('connection failed to peer: '+ws.url+" "+ws._socket.remoteAddress+":"+ws._socket.remotePort);
sockets.splice(sockets.indexOf(ws),1);
}
ws.on('close',()=>closeConnection(ws));
ws.on('error',()=>closeConnection(ws))
}
当连接错误时,关掉它
var write=(ws,message)=>{
console.log("fa song gei le:"+ws._socket.remoteAddress+":"+ws._socket.remotePort)
ws.send(message)
}
var broadcast=(message)=>{
sockets.forEach(socket =>write(socket,message));
}
initHttpServer();
initP2PServer();
最后就是brocast如何广播的,也就是调用一下socket.send()
内个forEach写个普通for循环一样的
如果有说的不对的地方或者是建议欢迎指正…