単純なパイプラインがあります。
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";
}'
または名前が付けられていない2つのパイプ(例:ㅏcoproc
。
そして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
のx>>|y
パイプ演算子を使用してください:
{ node foo.js <&3 3<&- | node bar.js 3<&-; } >>|3
答え2
いいえ。パイプは一方向通信チャネルです。これが「パイプライン」と呼ばれる理由です。いくら試しても石油をパイプラインに戻すことはできません。
ただし、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つのスクリプトのいずれかを別のホストに簡単に移行できます。
いずれにしても、スクリプトが双方向で通信している場合は、明確にするために、あるプロセスをパイプを介して別のプロセスに接続するのではなく、別のプロセスで開始することをお勧めします。 IMHO、彼らは現在同等のパートナーであり、コマンドラインにそれを表示する必要があります。しかし、これは単なる詳細であり、技術的に必ずしも必要ではありません。
答え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ドメインを使用することです。ソケット。