在管道中向后通信

Ale*_*lls 6 pipe stdout stdin stderr stdio

我有一个简单的管道:

node foo.js | node bar.js
Run Code Online (Sandbox Code Playgroud)

bar.js将从 stdin 读取以从foo.js.

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

foo 写入标准输出 --> bar 从标准输入读取 --> bar 如何将消息发送回 foo?

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

Wou*_*lst 5

不可以。管道是一种单向通信渠道。这就是为什么它被称为“管道”的原因;如果您尝试过,您也无法将石油送回管道。

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

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

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

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

  • 在许多系统上,管道是双向的,Linux 是一个明显的例外。socketpair() 是一种更便携的双向管道方式(请注意,`ksh93` 使用 socketpair() 作为其 `|` 运算符,但关闭相反方向)。 (2认同)

Sté*_*las 5

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

node foo.js <&1 | node bar.js >&0
Run Code Online (Sandbox Code Playgroud)

除了已经提到的命名管道,您还可以使用 socketpair:

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";
  }'
Run Code Online (Sandbox Code Playgroud)

两个命名管道,例如使用一个coproc

zsh

coproc node foo.js
node bar.js <&p >&p
Run Code Online (Sandbox Code Playgroud)

ksh

node foo.js |&
node bar.js <&p >&p
Run Code Online (Sandbox Code Playgroud)

bash 4+:

coproc node foo.js
node bar.js <&"${COPROC[0]}" >&"${COPROC[1]}"
Run Code Online (Sandbox Code Playgroud)

或 withyashx>>|y管道运算符:

{ node foo.js <&3 3<&- | node bar.js 3<&-; } >>|3
Run Code Online (Sandbox Code Playgroud)