web-dev-qa-db-ja.com

パイプで逆方向に通信する

私は単純なパイプラインを持っています:

node foo.js | node bar.js

bar.jsはstdinから読み取り、foo.jsからデータを取得します。

しかし、私がやりたいことは、foo.jsが終了してもよいと判断する前に、bar.jsfoo.jsから最後のメッセージの1つを取得するようにすることです。基本的に、単純な要求/応答パターンを作成したいと思います。

fooはstdoutに書き込みます-> barはstdinから読み取ります-> barはどのようにしてfooにメッセージを送り返すことができますか?

パイプラインで逆方向に通信する方法はありますか?それを行う必要はありませんか?

6
Alexander Mills

いいえ。パイプラインは一方向の通信チャネルです。これが「パイプライン」と呼ばれる理由です。オイルをパイプラインに戻すこともできませんでした。

ただし、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を引き続き使用するため(名前付きパイプを開くには、ファイルシステム上のファイルを開く必要があります)、移行が最も簡単ですが、一方向です(ただし、各方向に1つずつ、2つのチャネルがあります)。 。前者は少しクリーンで、2つのスクリプトのいずれかが必要になった場合に、別のホストに簡単に移行できます。

とにかく、スクリプトが双方向で通信している場合は、わかりやすくするために、1つのプロセスを他のプロセスにパイプするのではなく、別々のプロセスとして開始することをお勧めします。私見、彼らは今や同等のパートナーであり、あなたのコマンドラインはそれを示すはずです。ただし、これは単なる詳細であり、技術的には必須ではありません。

5
Wouter Verhelst

パイプが双方向であるシステム(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";
  }'

または、たとえば a coproc を使用する2つの名前のないパイプ。

zshの場合:

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

ksh

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

bash 4+:

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

またはyash 's x>>|yパイプ演算子:

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

おそらくお勧めしませんが、逆方向の通信は非常に簡単です。もちろん、間違った方法で通信することにより、複雑なシステムで本当に素晴らしい/不快なフィードバックループが発生する可能性があります。

* 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ドメインソケットを使用します。

0
Alexander Mills