我们都知道 Node 没法操作线程,但可以操作进程,一旦涉及主从模式的进程守护,或者是多机部署的需要,那么都可能碰上需要相互通信的场景,本篇就介绍几种常用方法。
最自然的方式,比上一种“正规”一些,具有同样的局限性。其底层是 libuv。
父
// parent.js
const cp = require(‘child_process‘);
const n = cp.fork(`child.js`);
n.on(‘message‘, (m) => {
console.log(‘父进程收到消息‘, m);
});
// 使子进程输出: 子进程收到消息 { hello: ‘world‘ }
n.send({ hello: ‘world‘ });
子
// child.js
process.on(‘message‘, (m) => {
console.log(‘子进程收到消息‘, m);
});
// 使父进程输出: 父进程收到消息 { foo: ‘bar‘, baz: null }
process.send({ foo: ‘bar‘, baz: NaN });
运行
> node parent.js
子进程收到消息 { hello: ‘world‘ }
父进程收到消息 { foo: ‘bar‘, baz: null }
libuv 的进程通信能力是怎么来的?
这就要涉及到操作系统的进程间通信方式了,参见深刻理解Linux进程间通信(IPC)。进程间通信一般通过共享内存的方式实现的,使得多个进程可以访问同一块内存空间,是最快的可用 IPC 形式。
最通用的方式,借助网络完成进程通信,有良好的跨环境能力,但存在网络的性能损耗。
父
// parent.js
const { spawn } = require(‘child_process‘);
const child = spawn(‘node‘, [‘child‘], {
stdio: [null, null, null, ‘pipe‘],
});
child.stdio[3].on(‘data‘, data => {
console.log(‘222‘, data.toString());
});
子
// child.js
const net = require(‘net‘);
const pipe = net.Socket({ fd: 3 });
pipe.write(‘killme‘);
运行
> node parent.js
222 killme
最强大的方式,既然要通信,场景还复杂,不妨扩展出一层消息中间件,漂亮地解决各种通信问题.
消息队列可以参见 Rabitmq
或者使用 Redis 的订阅发布,见下例
父
// parent.js
const cp = require(‘child_process‘);
const child = cp.fork(`child.js`);
var Redis = require("ioredis");
var redis = new Redis();
var pub = new Redis();
// 订阅 news 通道,
redis.subscribe("news", function (err, count) {
// `count` represents the number of channels we are currently subscribed to.
});
// 监听 message 事件。
redis.on("message", function (channel, message) {
// Receive message Hello world! from channel news
// Receive message Hello again! from channel music
console.log("Receive message %s from channel %s", message, channel);
}
子
// child.js
var Redis = require("ioredis");
var pub = new Redis();
// 发布新消息
pub.publish("news", "Hello world!");
pub.publish("music", "Hello again!");
单机使用则直接 Node 原生 IPC 最为省事,就如 EggJS 中 Master 进程与 Worker 进程的通信。
但你的服务负载需要部署去了多台机器,笔者更建议使用消息队列的方式来相互通信,毕竟追踪多机的 websocket 链路,是挺头疼的一件事。
原文:https://www.cnblogs.com/everlose/p/12846737.html