ZeroMQ PUSH/PULL 通信不能通过 IPC 工作,但可以通过 TCP 工作

ZeroMQ PUSH/PULL communication doesn't work via IPC, but it works via TCP

这是一本名为“Node.js 8 the Right Way”的书中的一个任务。 您可以在下面看到它:

这是我的解决方案:

'use strict';
const zmq = require('zeromq');
const cluster = require('cluster');

const push = zmq.socket('push');
const pull = zmq.socket('pull');

const cores_num = require('os').cpus().length;
let workers_num = 0;

push.bind('tcp://127.0.0.1:9998');
pull.bind('tcp://127.0.0.1:9999');
// push.bind('ipc://push.ipc');
// pull.bind('ipc://pull.ipc');

if (cluster.isMaster) {
  for (let j = 0; j < cores_num; j++) {
    cluster.fork();
  }

  cluster.on('online', (worker) => {
    console.log(`Worker with pid ${worker.process.pid} is created!`);
  });

  pull.on('message', (data) => {
    const response = JSON.parse(data.toString());

    if (response.type === 'ready') {
      if (workers_num >= 0 && workers_num < 3) {
        workers_num++;

        if (workers_num == 3) {
          console.log('Ready!');

          for (let i = 0; i < 10; i++) {
            push.send(JSON.stringify({
              type: 'job',
              data: `This message has id ${i}`
            }));
          }
        }
      }
    } else if (response.type === 'result') {
      console.log(data.toString());
    }
  });
} else {
  const worker_push = zmq.socket('push');
  const worker_pull = zmq.socket('pull');

  worker_pull.connect('tcp://127.0.0.1:9998');
  worker_push.connect('tcp://127.0.0.1:9999');
  // worker_pull.connect('ipc://push.ipc');
  // worker_push.connect('ipc://pull.ipc');

  worker_push.send(JSON.stringify({
    type: 'ready'
  }));

  worker_pull.on('message', data => {
    const request = JSON.parse(data);

    if (request.type === 'job') {
      console.log(`Process ${process.pid} got message ${request.data}`);
      worker_push.send(JSON.stringify({
        type: 'result',
        data: `This message is a response from process ${process.pid}`,
        time: Date.now()
      }));
    }
  });
}

正如你所看到的,它只在PUSH/PULL套接字和工人通过TCP通信时有效,但我想知道它不能通过IPC工作的原因。

更新(参考:下面的条件 4 "pathname must be writeable"): 希望大家帮我解决问题

I want to know the reason why it doesn't work via IPC.

使用 ipc:// transport-class 使用 ZeroMQ 可扩展正式通信原型并获得 .bind()/.connect()-ed

1) inter-process 传输使用 system-dependent IPC 机制在本地进程之间传递消息。 inter-process 传输目前 仅在提供 UNIX 域套接字的操作系统上实现。

2) .bind()端和.connect()端都需要在某个可行的地址:

相遇
          push.bind(    'ipc://push.sock'     ); // will never meet its counterparty
 // ------------------(--|||://^v^v^v^v^v^v^v )
   worker_pull.connect( 'ipc:///tmp/push.sock'); //         if used other ipc://-address

3) 如果任何第二个进程绑定到一个已被进程绑定的端点,这将成功并且第一个进程将失去其绑定。在此行为中,ipc:// transport-class 与 tcp://inproc:// transport-class 不一致。

4) endpoint-address 路径名 必须 可由进程写入。当端点以 / 开头时,例如 ipc:///pathname,这将是一个绝对路径名。如果端点指定的目录不存在,则绑定失败。

5) 当endpoint-address路径名以@开头时,应使用抽象命名空间。抽象命名空间独立于文件系统,如果一个进程试图绑定一个已经被进程绑定的端点,它将失败。有关详细信息,请参阅 unix(7)。

6) ipc:// transport-class 路径名的最大大小取决于操作系统。在 Linux 上,包括“ipc://”前缀在内的最大值为 113 个字符(实际路径名为 107 个字符)。

7) 当在 zmq_bind() 中使用了 wild-card * 端点规范时,调用者 应该 使用从 [=41= 获得的真实端点]ZMQ_LAST_ENDPOINT 套接字选项,使用 zmq_unbind().

将此端点与套接字解除绑定

几件事:

您的 IPC 路径不正确:

您有 ipc://push.ipc(2 个斜杠),您确实需要 ipc:///push.ipc 协议是 ipc:// 然后你需要文件路径 /push.ipc

文件权限:

你的进程是否有写入根目录的权限?除非你是运行宁作为根我认为不会。

我会将路径更改为类似 /tmp/push.ipc 的路径,在大多数系统中所有用户都可以写入该路径。

在这种情况下,您的 url 应该是:

ipc:///tmp/push.ipc

分叉

我根本不使用节点,但根据我对其他语言的了解,我认为整个程序在不同的 process/thread.

中再次 运行

在这种情况下,不是每个工作人员都试图再次 bind(),因为套接字 creation/bind 代码在 if (cluster.isMaster) {

之外

我觉得应该是这样的

if (cluster.isMaster) {

  const push = zmq.socket('push');
  const pull = zmq.socket('pull');
  push.bind('ipc://push.ipc');
  pull.bind('ipc://pull.ipc');
  ....
}