Netcat/socat behavior with piping and UDP?

I guess this is close to linux - Netcat stops listening for UDP traffic - Super User, but I thought I'd better ask anyways

As far as versions of netcat I'm using Ubuntu 11.04 and the default netcat on it, which I'm guessing is the openbsd one:

$ nc
This is nc from the netcat-openbsd package. An alternative nc is available
in the netcat-traditional package.
usage: nc [-46DdhklnrStUuvzC] [-i interval] [-P proxy_username] [-p source_port]
      [-s source_ip_address] [-T ToS] [-w timeout] [-X proxy_protocol]
      [-x proxy_address[:port]] [hostname] [port[s]]

 

This is what I find strange: the first case works as expected - I open a UDP server in one terminal:

$ sudo nc -ul 5000

... and in another terminal I initiate a new UDP client connection - and I type in hello three times, pressing ENTER after each:

$ nc -u 127.0.0.1 5000
hello
hello
hello
^C

... and going back to the server terminal, it has printed hello three times, as expected:

$ sudo nc -ul 5000 
hello
hello
hello
^C

 

So far so good, all works as expected. However, let's say I try now the same by piping input into the client; so establish first a UDP server in one terminal:

$ sudo nc -ul 5000

... and in another, pipe some data into nc as UDP client:

$ echo hello | nc -u 127.0.0.1 5000
hello
hello
^C

... after the client command, the shell sort of freezes as if waiting for input - so there I type hello and ENTER two more times; but the server has registered only the first hello (which was piped via echo). Furthermore, even if you press Ctrl-C, and try to repeat the client echo hello | nc -u 127.0.0.1 5000 command, the server will still remain on having reported just the very first hello:

$ sudo nc -ul 57130 
hello
^C

... and only after stopping the server with Ctrl-C and restarting it again, can one repeat the client echo hello | nc -u 127.0.0.1 5000 command and observe it working.

 

Is this the way nc is supposed to be behaving? I would expect that at least repeated calls to echo hello | nc -u 127.0.0.1 5000 would be registered - without having to restart the server? Or maybe there is a special command-line switch for that kind of behavior?

EDIT: I found this nice PDF presentation: socat – Handling all Kinds of Sockets, which contains the following netcat vs socat notes:

netcat - Limitations
● one-shot only (terminates after socket close)
...
Examples 1: netcat Replacement
...
● UDP client with source port:
nc -­u ­-p 500 1.2.3.4 500
socat ­- udp:1.2.3.4:500,sp=500
● TCP server:
nc ­-l ­-p 8080
socat ­- tcp­-l:8080,reuseaddr
...

... however, I'm pretty much getting the same behavior as above, if I replace the server command with "socat - udp4-listen:5000,reuseaddr" - and the client line with "socat - udp:127.0.0.1:5000"... With the piped input, "echo hello | socat - udp:127.0.0.1:5000", the only difference is that here the command at least exists after the word hello had been sent - however, again, consecutive runs of this command will not cause any reception at the server, until the server is restarted.


Ok, I think at least I got something with socat - namely, the option fork needs to be appended to the server line:

$ socat - udp4-listen:5000,reuseaddr,fork

... and then, in another terminal, we can call echo piping into socat client line multiple times on command line, as it will exit immediately (well, after half a second :)):

$ echo "hello" | socat - udp-sendto:127.0.0.1:5000
$ echo "hello" | socat - udp-sendto:127.0.0.1:5000
$ echo "hello" | socat - udp-sendto:127.0.0.1:5000

... and going back to the first terminal, we can see that the server has successfully shown all three hellos:

$ socat - udp4-listen:5000,reuseaddr,fork
hello
hello
hello
^C

 

Note that even with a fork-ed socat server, the line echo "hello" | nc -u 127.0.0.1 5000 will still 'lock' as if waiting for user input; however, now after Ctrl-C and re-running the command, i.e.

$ echo "hello" | nc -u 127.0.0.1 5000
^C
$ echo "hello" | nc -u 127.0.0.1 5000
^C
$ echo "hello" | nc -u 127.0.0.1 5000
^C

... the fork-ed socat server will show three hellos without the need to be restarted..

 

Seemingly, this openBSD netcat doesn't have a fork option - but I'm not sure if it has one that is corresponding to it..

Anyways, hope this helps someone,
Cheers!


Your netcat is only reading the output from echo's stdout when you use pipe, it's not "connected" to the keyboard anymore. To get the response you're expecting, you can add your three "hello"'s to a file an run

cat [myfile] | nc -u 127.0.0.1 5000

If you do an strace of the listening nc, it will show that netcat is waiting for the connection, and once it gets it, will connect to that host and port, ignoring all others. You need to add '-k' to keep going and '-w 0' to timeout each connection after 0 seconds. Socat is a better choice, I think.