I want to use netcat as a TCP-server that reads data from a named pipe. For that I did the following:

Step 1. Created a pipe and the server that uses it as a source

mkfifo /tmp/all.pipe
nc -k -l 8080 < /tmp/all.pipe

Step 2. Created a client that reads the data continuously:

while true; do
    sleep 1;
    echo "Check connection";
    while IFS= read -r line; do
        printf "$line";
    done < /dev/tcp/localhost/8080;

Step 3. Write some data to the pipe:

echo "hello" > /tmp/all.pipe

After execution of these 3 steps the output on the client side was:

bash: connect: Connection refused
bash: /dev/tcp/localhost/8080: Connection refused
Check connection
bash: connect: Connection refused
bash: /dev/tcp/localhost/8080: Connection refused
Check connection

However when I executed the step 3 after this again, the output didn't change. Looks like it happened because the connection was still active, but the new data wasn't passed from the pipe to the nc and then to the client. Why? What can be done to achieve it?

1 Answer 1



nc -k -l 8080 < /tmp/all.pipe

The shell tries to open /tmp/all.pipe and that hangs as there's no process that has opened the named pipe for writing yet.

Since nc has not been started yet, that explains why bash gets a connection refused when trying to connect there.

When you do

echo "hello" > /tmp/all.pipe

Then that's when the first command is unlocked. The pipe is now instantiated.

Then echo writes hello\n there and terminates, at which point the writing end of the pipe is closed, and nc will see end-of-file on its stdin. If you had used cat instead of nc, cat would have terminated.

But for nc, its stdout still goes to the terminal at that point and the TCP connection is still live so even if there's one end that has reached end-of-input, it carries on. If bash sent something on that socket, that would be displayed on nc's stdout for instance.

When you do a second echo something > /tmp/all.pipe, as nc has not closed its fd on the pipe (at least that's the case of the nc from the netcat-openbsd package on Ubuntu, YMMV), that does go through that same pipe that goes live again, but nc has already given up reading from that since it had reached eof earlier.

Easiest here is probably to open the pipe for nc's input in read+write mode so it's instantiated immediately and always live as long as nc lives.

For that, just replace < with <> on the nc command line:

nc -k -l 8080 <> /tmp/all.pipe

Also note that the first argument to printf is the format, you shouldn't have any variable there. If you want to print the input line without the line delimiter, you use:

printf %s "$line"

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .