%20%E3%81%AE%E9%81%95%E3%81%84%E3%81%AF%E4%BD%95%E3%81%A7%E3%81%99%E3%81%8B%3F.png)
nc
私の目標は、と単一のを使用して単純なエコー サーバーを作成することですfifo
。最善の方法を探しているわけではなく、次のコマンドのセマンティクス (フォークがいつ発生するか、なぜ発生するか、何が変更されるか、コマンドの動作が異なるのはなぜかなど) を理解しようとしているだけです。
sh
私は Bash を使用しているので、すべてのコマンドが POSIXまたはzsh
、 、で動作するかどうかはわかりませんksh
。
タイトルで言及している 4 つのコマンドは次のとおりです (すでに実行済みであると仮定しますmkfifo fifo
)。
cat fifo | nc -l localhost 8888 > fifo
exec 3<> fifo && nc -l localhost 8888 <&3 >&3 && exec 3>&-
nc -l localhost 8888 <(cat fifo) > fifo
nc -l localhost 8888 < fifo > fifo
ここで、4 つのコマンドが同じことを実行し、少なくとも最後の 2 つのコマンドは同じことを実行すると予想します。
- 最初のコマンドは期待どおりに動作し、クライアントが接続を閉じるとシャットダウンする単純なエコー サーバーになります。
- 1 のように動作します。
- サーバーに接続してデータを送信できますが、何も返ってきません。クライアント接続を閉じると、サーバーがシャットダウンします。
- サーバーに接続できません。サーバーは永久にリッスンし続けます。
答え1
ここで重要なのは、FIFO を開くことはブロッキング操作であるということです。open
両端が接続されたとき、つまり FIFO が読み取りと書き込みの両方に対して開かれたときのみ、戻ります。
Normally, opening the FIFO blocks until the other end is opened also.
1 番目のケースでは、シェルはパイプラインを実行するためにフォークするため、読み取り用に fifo を開く ( cat fifo
) ことと、書き込み用に fifo を開く ( > fifo
) ことは別々のプロセスで行われるため、独立して発生します。
2 番目のケースでは、読み取り用のオープンと書き込み用のオープン ( 3<>fifo
) が 1 つのステップで実行されます。
3 番目のケースでは、<(cat fifo)
はファイル名に展開されます (例: ) /dev/fd/42
。つまり、 を実行しているのと同じです。同等にするには、 の ようにnc -l localhost 8888 /dev/fd/42 > fifo
追加の が必要です(例: ) 。<
nc -l localhost 8888 < <(cat fifo) > fifo
4 番目のケースでは、シェルは fifo を読み取り用に開こうとしています ( < fifo
)、> fifo
同じプロセスの一部として書き込み用に開こうとしています ( )。シェルは、これらを左から右に 1 つずつ実行します。つまり、fifo
読み取り用に開こうとしますが、書き込み用に何かが開くのを待って永久にブロックします。このケースでは、開始すらされず、ポートがリスニング用に開かれなかったことfifo
がわかると思います。nc