如何用net 创建多路复用的RPC通道
先导语
我们前面学习了什么是RPC通道,今天就来尝试使用node的net模块来实现一下RPC通道。
关于net
net模块和http模块的用法类似,详情请看:nodejs.org/dist/latest…
使用net创建一个单工通信的RPC通道
- 首先先创建两个js文件,分别是:client和server
- 然后在server文件里面引入net模块,并使用net模块创建一个服务器,然后监听4000端口(端口号可以自定,我这里监听的是4000端口),代码如下:
const net = require("net"); //引入net模块
// 创建server
// socket:网络通道中写入和取出的一个代理对象
let server = net.createServer((socket) => {
socket.on("data", (buffer) => {
// 监听data事件
console.log(buffer, buffer.toString());
});
});
server.listen(4000);
- 在client文件里面同样引入net模块,创建一个Socket对象,该Socket对象连接server服务器,然后就可以使用socket.write的方法去写入需要发送的内容了。代码如下:
const net = require("net");
let socket = new net.Socket({}); //创建socket对象
//连接server服务器
socket.connect({
host: "127.0.0.1",
port: 4000,
});
socket.write("hello wlf"); //发送
- 分别启动client和server服务器,server端就可以得到client端发送过来的内容了。
使用net创建一个半双工通信的RPC通道
半双工通信的特点是:只有当上一次的请求返回结果之后,才能发送下一次请求! client端代码如下:
const net = require("net");
let socket = new net.Socket({}); //创建socket对象
//连接server服务器
socket.connect({
host: "127.0.0.1",
port: 4000,
});
socket.write(send(Math.floor(Math.random() * 8))); //发送
socket.on("data", (buffer) => {
console.log(buffer.toString());
//每次得到一个结果之后,设置一个定时器,规定两秒后继续发送消息
setTimeout(() => {
socket.write(send(Math.floor(Math.random() * 8))); //发送
}, 2000);
});
// 将发送消息的代码封装成一个方法
function send(id) {
let buf = Buffer.alloc(2);
buf.writeInt16BE(id, 0);
return buf;
}
server端代码:
const net = require("net"); //引入net模块
// 创建server
// socket:网络通道中写入和取出的一个代理对象
let server = net.createServer((socket) => {
socket.on("data", (buffer) => {
// 监听data事件
let dataId = buffer.readInt16BE();
console.log(dataId);
socket.write(Buffer.from(data[dataId]));
});
});
server.listen(4000);
//数据
let data = {
0: "柳宗元",
1: "韩愈",
2: "欧阳修",
3: "苏洵",
4: "苏轼",
5: "苏辙",
6: "王安石",
7: "曾巩",
};
结果:每个两秒之后发起一次请求并接收到一个结果。
双工通信
双工通信的特点是:自由的发送和返回消息,根据双工通信的这个特点,我们的代码可能会遇到一个问题:如何确定发送的消息和返回的消息之间的对应关系? 我们画图来解释下这个问题:
如上图:当client端几乎同时发送了两条消息,分别是msg1和msg2,这个时候server端接收到两条消息,然后开始处理,首先返回出去的是msg2的处理结果,然后才是msg1的处理结果,这个时候client端如何将得到的数据跟发送的数据对应起来呢?
要解决这个问题,我们需要在发送和返回的数据中加上相同的一个标识id。
client端代码:
const net = require("net");
let socket = new net.Socket({}); //创建socket对象
//连接server服务器
socket.connect({
host: "127.0.0.1",
port: 4000,
});
// 每50ms发一个包
setInterval(() => {
socket.write(send(Math.floor(Math.random() * 8))); //发送
}, 50);
socket.on("data", (buffer) => {
console.log(buffer.slice(0, 2).readInt16BE(0), buffer.slice(2).toString());
});
// 将发送消息的代码封装成一个方法
let flagId = 0; //标识ID
function send(id) {
let buf = Buffer.alloc(4);
buf.writeInt16BE(flagId, 0); //把标识ID放在buffer头部
buf.writeInt16BE(id, 2);
flagId++;
return buf;
}
server端代码:
const net = require("net"); //引入net模块
// 创建server
// socket:网络通道中写入和取出的一个代理对象
let server = net.createServer((socket) => {
socket.on("data", (buffer) => {
// 监听data事件
let flagBuf = buffer.slice(0, 2); //取出标识ID
let dataId = buffer.readInt16BE(2);//读出id
console.log(flagBuf.readInt16BE(0), dataId);
// 定时器乱序返回结果
setTimeout(() => {
socket.write(Buffer.concat([flagBuf, Buffer.from(data[dataId])])); //使用concat连接要返回的内容和标识ID
}, 1000 * Math.random() + 10);
});
});
server.listen(4000);
//数据
let data = {
0: "柳宗元",
1: "韩愈",
2: "欧阳修",
3: "苏洵",
4: "苏轼",
5: "苏辙",
6: "王安石",
7: "曾巩",
};
client端结果:
server端结果:
对比client端和server端可以判单返回数据是否正确。
结束语
今天我们学习了如何使用node的net模块来创建简单的多路复用的RPC通道。通过学习这一节的内容,让我对RPC通道的理解更深刻了。那么,下次见!好好学习,天天向上!