为什么我的请求和响应消息乱序?

Why are my request and response messages out of order?

我正在阅读一本教您 Node.JS 基础知识的书,并且我创建了几个程序 - 一个响应程序和一个请求程序。

回复者:

"use strict";

const fs = require("fs");
const zmq = require("zmq");
const responder = zmq.socket("rep"); // Create socket to reply to client requests

// Handle incoming requests
responder.on("message", function(data) {
    // Parse incoming message
    let request = JSON.parse(data);
    console.log("Received request to get: " + request.path);

    // Read file and reply with content
    fs.readFile(request.path, function(err, content) {
        console.log("Sending response content");
        responder.send(JSON.stringify({
            content: content.toString(),
            timestamp: Date.now(),
            pid: process.pid
        }));
    });
});

// Listen on TCP port 5433
responder.bind("tcp://127.0.0.1:5433", function(err) {
    console.log("Listening for zmq requesters...");
});

// Close the responder when the Node process ends
process.on("SIGINT", function() {
    console.log("Shutting down...");
    responder.close();
});

请求者:

"use strict";

const zmq = require("zmq");
const filename = process.argv[2];
const requester = zmq.socket("req"); // Create request endpoint

// Handle replies from responder
requester.on("message", function(data) {
    let response = JSON.parse(data);
    console.log("Received response:", response);
});

requester.connect("tcp://localhost:5433");

// Send request for content
for (let i=1; i <= 3; i++) {
    console.log("Sending request " + i + " for " + filename);
    requester.send(JSON.stringify({
        path: filename
    }));
}

所以我 运行 启动正常的响应程序,然后我 运行 像这样的请求程序(target.txt 已经存在于文件系统中):

> node requester.js target.txt

奇怪的是,给定 Node.js 的单线程,我希望输出 always 是:

Sending request 1 for target.txt
Sending request 2 for target.txt
Sending request 3 for target.txt
Received response: { ...

然而,有时我明白了,但有时我得到:

Sending request 1 for target.txt
Sending request 2 for target.txt
Received response: { ...
Sending request 3 for target.txt

怎么会这样?事件循环正在执行我的 for 循环,这应该意味着 "Sending request" 行得到输出,然后它有机会调用响应处理程序。为什么我有时会在记录第三个请求之前收到响应?

在您的 responder 函数中读取文件时,您使用 fs.readFile 这是一个异步非阻塞函数(它将在新线程中读取文件)。这意味着它不会在接受新请求之前等待文件被读取。

如果你想使用同步函数你可以使用

fs.readFileSync

这将等待文件被完全读取然后发送响应。

很明显,只有在 send 实现中调用提供给 on 的回调时,您看到的行为才会发生。

zmq 模块包含本机代码。它以本机代码接收响应,然后将它们提供给 JavaScript 主机。它的响应接收与 JavaScript 事件循环无关。似乎在 send 实现中,如果响应可用,则会调用提供给 on 的回调。据推测,任何未在 send 调用中传递给回调的响应都将在下一回合通过事件循环传递。