在管道中向后通信

在管道中向后通信

我有一个简单的管道:

node foo.js | node bar.js

bar.js将从 stdin 读取以获取数据foo.js

但我想做的是确保在foo.js 决定可以退出之前bar.js获取最后一条消息。foo.js本质上我想创建一个简单的请求/响应模式。

foo 写入 stdout --> bar 从 stdin 读取 --> bar 如何将消息发送回 foo?

有没有办法在管道中向后通信,或者永远不需要这样做?

答案1

在管道是双向的系统上(NetBSD、FreeBSD、SVR4 派生的 Unices(所有管道至少使用 STREAMS 的系统),但不是 Linux):

node foo.js <&1 | node bar.js >&0

除了已经提到的命名管道之外,您还可以使用套接字对:

perl -MSocket -e '
  socketpair(A, B, AF_UNIX, SOCK_STREAM, PF_UNSPEC);
  if (fork) {
    open STDIN, "<&A";
    open STDOUT, ">&B";
    exec "node", "foo.js";
  } else {
    open STDIN, "<&B";
    open STDOUT, ">&A";
    exec "node", "bar.js";
  }'

或者两个无名管道,例如使用Acoproc

zsh

coproc node foo.js
node bar.js <&p >&p

ksh

node foo.js |&
node bar.js <&p >&p

bash4+:

coproc node foo.js
node bar.js <&"${COPROC[0]}" >&"${COPROC[1]}"

或者使用yash'sx>>|y管道运算符:

{ node foo.js <&3 3<&- | node bar.js 3<&-; } >>|3

答案2

不。管道是一种单向通信通道。这就是为什么它被称为“管道”;即使你尝试,也无法将石油送回管道。

但是,如果 bar.js 也必须与 foo.js 通信,那么您有几个选择:

  • 创建一个 unix 域套接字而不是管道,并分别启动两者foo.jsbar.js即,不再将 foo.js 的输出通过管道传输到 bar.js 中)。我不知道如何从节点做到这一点,但本质上,unix 域套接字是一个网络套接字,它使用文件名而不是 IP 地址,并在内核内部工作。套接字用于双向通信,但需要比简单管道更多的设置(例如,侦听套接字可以与 bar.js 的多个实例通信)。您可能会在文件系统中找到 unix 域套接字,但这并不是绝对必要的(实际上 Linux 允许创建 unix 域套接字而不在文件系统上留下痕迹)。
  • 用于mkfifo创建命名管道(或使用某些节点 API 来创建一个命名管道,如果存在的话;同样,我不知道节点)。然后,在 中foo.js,打开该命名管道并从中读取。您的bar.js脚本可以打开相同的命名管道并向其写入。

后者最容易过渡到,因为您仍然使用文件 I/O(打开命名管道需要在文件系统上打开文件),但仍然是单向的(尽管您有两个通道,每个方向一个) 。前者稍微干净一些,并且还允许您在必要时更轻松地将两个脚本之一迁移到不同的主机。

无论如何,如果您的脚本现在是双向通信的,那么为了清楚起见,我建议您将它们作为单独的进程启动,而不是让一个进程通过管道连接到另一个进程。恕我直言,他们现在是平等的伙伴,你的命令行应该显示这一点。但这只是一个细节,当然不是技术上必需的。

答案3

向后通信非常容易,尽管可能不推荐。当然,通过错误的沟通方式,您可能会在复杂的系统中得到一些非常好的/不愉快的反馈循环。

在 *nix 上,您可以使用 Node.js 执行此操作,如下所示:

// foo.js
process.stdout.write(process.pid);

// bar.js
process.stdin.resume().once('data', function(pid){

   const writable = fs.createWriteStream(`/proc/${pid}/fd/0`);
   writable.write('whatevs');  // write to stdin of foo.js

});

上面是简化的,但你明白了。理想情况下,您可以使用 JSON 对 stdio 消息进行编码。这是一个很好的库来做到这一点:https://github.com/ORESoftware/json-stdio

然而,问题是,在MacOS上,你没有能力使用/proc/<pid>...上次我检查过,唯一的好方法是使用为这种情况mkfifo创建一个唯一的fifo,或者使用TCP或Unix域套接字。

相关内容