Node 版本 10.16.0 ZeroMQ 版本 5.1.0 使用 ZeroMQ 的代码如下:
服务端 /zmq-rep.js
"use strict";
const fs = require("fs");
const zmq = require("zeromq");
const moment = require("moment");
const responder = zmq.socket("rep");
responder.on("message", data => {
let reqData = JSON.parse(data);
let filename = reqData.path;
console.log(`Request received:${filename}`);
fs.readFile(filename, (err, data) => {
if (err) {
throw Error(err);
}
console.log(`Sending response for ${filename} at ${moment().format()}`);
responder.send(
JSON.stringify({
content: data.toString(),
timestamp: moment().format("x"),
pid: process.pid
})
);
});
});
responder.bind("tcp://127.0.0.1:50221", err => {
if (err) {
throw Error(err);
}
console.log("Now listening for requests...");
});
process.on("SIGINT", () => {
console.log("Now closing server...");
responder.close();
});
客户端 /zmq-req.js
"use strict";
const zmq = require("zeromq");
const moment = require("moment");
const filename = process.argv[2];
const request = zmq.socket("req");
request.on("message", data => {
let response = JSON.parse(data);
console.log(
`Fetch file content:${response.content} at ${
response.timestamp
} processed by ${response.pid}`
);
});
request.connect("tcp://127.0.0.1:50221");
for (let i = 1; i <= 5; i++) {
console.log(
`Sending request to get ${filename} for ${i} time(s) at ${moment().format()}`
);
request.send(
JSON.stringify({
path: filename
})
);
}
使用如下方式调用:
# Terminal 1
$ node zmq-rep.js
# Terminal 2
$ node zmq-req.js target.txt
服务端输出如下:
Now listening for requests...
Request received:target.txt
Sending response for target.txt at 2019-07-27T07:36:47+08:00
Request received:target.txt
Sending response for target.txt at 2019-07-27T07:36:47+08:00
Request received:target.txt
Sending response for target.txt at 2019-07-27T07:36:47+08:00
Request received:target.txt
Sending response for target.txt at 2019-07-27T07:36:47+08:00
Request received:target.txt
Sending response for target.txt at 2019-07-27T07:36:47+08:00
客户端输出如下
Sending request to get target.txt for 1 time(s) at 2019-07-27T07:36:47+08:00
Sending request to get target.txt for 2 time(s) at 2019-07-27T07:36:47+08:00
Sending request to get target.txt for 3 time(s) at 2019-07-27T07:36:47+08:00
Sending request to get target.txt for 4 time(s) at 2019-07-27T07:36:47+08:00
Sending request to get target.txt for 5 time(s) at 2019-07-27T07:36:47+08:00
Fetch file content:50221 at 1564184207708 processed by 12984
Fetch file content:50221 at 1564184207734 processed by 12984
Fetch file content:50221 at 1564184207747 processed by 12984
Fetch file content:50221 at 1564184207766 processed by 12984
Fetch file content:50221 at 1564184207794 processed by 12984
可以看到,客户端代码发送请求是非阻塞的,但服务端代码是阻塞的。《 Node.js 8 the right way 》对这个现象的解释是:"Node.js event loop was left spinning while the fs.readFile for each request was being processed."但查阅文档,fs.readFile 本身是非阻塞的,如果这一解释成立的话,fs.readFile 不就是阻塞函数了吗?
我另外写了一份只使用 net 模块进行通讯的代码,现象与使用 ZeroMQ 进行通信不同,在这种情况下,服务端的回调并没有阻塞。
服务端 /tcp-server.js
"use strict";
const fs = require("fs");
const net = require("net");
const moment = require("moment");
const server = net
.createServer(connection => {
console.log("Request received");
connection.on("data", data => {
let reqData = JSON.parse(data);
console.log(`Reading ${reqData.path} at ${moment().format()}`);
fs.readFile(reqData.path, (err, data) => {
connection.write(
JSON.stringify({
content: data.toString(),
timestamp: moment().format()
})
);
});
});
})
.listen({ port: 50221, hostname: "127.0.0.1" })
.on("listening", () => {
console.log("Now listening...");
});
客户端 /tcp-client.js
"use strict";
const net = require("net");
const filename = process.argv[2];
const connectionPool = [];
for (let i = 1; i <= 5; i++) {
connectionPool.push(
net
.createConnection(50221, "127.0.0.1", () => {
console.log(
`Connetcion ${i} established and start fetching file ${filename} on server...`
);
})
.on("data", data => {
console.log(`Receive response:${data}`);
})
);
}
connectionPool.forEach(connection => {
connection.write(
JSON.stringify({
path: filename
})
);
});
process.on("SIGINT", () => {
connectionPool.forEach(connection => {
connection.end();
});
});
调用如下:
# Terminal 1
$ node tcp-server.js
# Terminal 2
$ node tcp-client.js target.txt
客户端输出如下:
Connetcion 1 established and start fetching file target.txt on server...
Connetcion 2 established and start fetching file target.txt on server...
Connetcion 3 established and start fetching file target.txt on server...
Connetcion 4 established and start fetching file target.txt on server...
Connetcion 5 established and start fetching file target.txt on server...
Receive response:{"content":"50221","timestamp":"2019-07-27T07:44:53+08:00"}
Receive response:{"content":"50221","timestamp":"2019-07-27T07:44:53+08:00"}
Receive response:{"content":"50221","timestamp":"2019-07-27T07:44:53+08:00"}
Receive response:{"content":"50221","timestamp":"2019-07-27T07:44:53+08:00"}
Receive response:{"content":"50221","timestamp":"2019-07-27T07:44:53+08:00"}
服务端输出如下:
Now listening...
Request received
Request received
Request received
Request received
Request received
Reading target.txt at 2019-07-27T07:44:53+08:00
Reading target.txt at 2019-07-27T07:44:53+08:00
Reading target.txt at 2019-07-27T07:44:53+08:00
Reading target.txt at 2019-07-27T07:44:53+08:00
Reading target.txt at 2019-07-27T07:44:53+08:00
于是可以看到,不论在服务端还是客户端的 io 都是非阻塞的。
这种不同是否与 ZeroMQ 的实现有关呢?感谢大佬们的回复!
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.