8

My goal is to create a simple echo server using nc and a single fifo. I'm not looking for the best way to do it, I'm merely trying to understand the semantics of the following commands (when does fork happen, why, what does it change, why the commands behave differently...).

I'm using Bash, so I'm not sure if all of the commands will work with a POSIX sh or zsh, ksh, ...

Here are the four commands I'm mentioning in the title (assuming that I already did 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

Now I would expect the 4 commands to do the same thing, at the very least the two last ones to do the same thing.

  1. The first command behaves as expected, a simple echo server that shuts down when the client closes the connection.
  2. Behaves like 1.
  3. I can connect to the server, send data, but I never receive anything back. When I close the client connection, the server shuts down.
  4. Can't connect to the server, the server listens forever.
8

The key here is that opening a FIFO is a blocking operation. The open only returns once both ends are connected, i.e. once the fifo is open for both reading and writing.

man fifo(7)

Normally, opening the FIFO blocks until the other end is opened also.

In the 1st case, the shell forks to execute the pipeline, so opening the fifo for reading (cat fifo) and opening the fifo for writing (> fifo) happen in separate processes, so happen independently.

In the 2nd case, the open for reading and open for writing (3<>fifo) happen in a single step.

In the 3rd case, <(cat fifo) expands to a filename, e.g. /dev/fd/42. So it's like you're running nc -l localhost 8888 /dev/fd/42 > fifo. You need an extra < for it to be equivalent, e.g. nc -l localhost 8888 < <(cat fifo) > fifo.

In the 4th case, the shell is trying to open the fifo for reading (< fifo) and open it for writing (> fifo) as part of the same process. The shell does them one at a time, left to right. So it tries to open fifo for reading, and blocks forever, waiting for something to open fifo for writing. I think you'll find that in this case, nc never even got started, and the port was never opened for listening.

  • Oh yeah silly error in #3, but at the end the result stays the same. Just another question which is more curiosity than anything else, is exec the only way to open the fifo for r/w in a single step? And is there any other way to force the shell to fork like in #1? Thank you! – foo Jun 15 '14 at 11:04
  • nc ... <>fifo should be sufficient. gnu.org/software/bash/manual/html_node/Redirections.html – Mikel Jun 15 '14 at 17:08
  • 1
    The shell will fork any time you use a pipeline, subshell, or process substitution. – Mikel Jun 15 '14 at 17:12
  • 2
    Correction, you'll need nc ... <>fifo >&0, since <>fifo opens fifo for reading and writing on fd 0, and we want the output to go there too. – Mikel Jun 15 '14 at 17:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.