19

I'm trying to send a message through netcat. After sending the message, netcat must terminate.

I've tried the following:

cat tsmmessage.bin | nc -u localhost 4300
nc -u localhost 4300 < message.bin

The -q option states:

-q seconds

after EOF on stdin, wait the specified number of seconds and then quit. If seconds is negative, wait forever.

But

nc -q0 -u localhost 4300 < message.bin

also doesn't work.

What am I missing?

  • You should probably have used the -q 0 flag with the pipe solution (with cat) instead of with the redirection solution (< ) – Camion Feb 07 '22 at 14:30

5 Answers5

16

Assuming that after sending EOF connection will stay idle, you can use -w timeout option, which works for timeout being equal to zero (unlike stupid -q option...)

cat tsmmessage.bin | nc -u localhost 4300 -w0
Bora M. Alper
  • 320
  • 2
  • 10
  • 1
    This is the correct answer and must be the accepted one rather than -q. – ccpizza Nov 13 '17 at 18:07
  • 3
    zero time out doesn't work on my machine (debian stretch). it says invalid wait-time 0 – Anubis Apr 20 '18 at 10:47
  • On debian stretch and debain buster, -w0 doesn't work. I've used -w 1 instead (with the space) and it works fine – ciencia Apr 01 '21 at 11:00
  • Looking at the manpage, -q seems to be the right solution to THIS problem, though : This problem seems quite one way and doesn't suggest that the server side is replying anything on the connection. Why do you disregard the -q 0 solution ? To me it looks that that -w … is only useful if you want the receiver side to stop at the end of data. – Camion Feb 07 '22 at 14:59
  • Well, on Ubuntu 22.04, both -q0 and -w0 work with UDP and with TCP, so.... – Fritz Jan 27 '24 at 21:55
6

Without the -q flag your instance of netcat will wait forever. There's no "end of stream" message with UDP so there is no way for netcat to know that both stdin and the network connection have finished.

For example, using TCP/IP this works as expected:

nc -l localhost 4300                     # Window 1
nc localhost 4300 </etc/group            # Window 2

But as you have determined, using UDP/IP this never ends:

nc -u -l localhost 4300                  # Window 1
nc -u localhost 4300 </etc/group         # Window 2

This is where the -q flag comes in. But unfortunately it doesn't accept a value of 0. It also won't accept non-integer values. Here is the best alternative I can offer without recourse to timeout or some other external utility:

nc -u -l localhost 4300                  # Window 1
nc -q 1 -u localhost 4300 </etc/group    # Window 2

Even here, it's not possible to have the listening netcat time out gracefully. (The -w timeout option is ignored, and -q is irrelevant.) Something like this might be of use in a practical situation, so that the netcat is killed after 90 seconds:

timeout 90 nc -u -l localhost 4300       # Window 1
nc -q 1 -u localhost 4300 </etc/group    # Window 2
Chris Davies
  • 116,213
  • 16
  • 160
  • 287
  • -q 0 works for me. – AlikElzin-kilaka Nov 11 '18 at 08:52
  • @AlikElzin-kilaka doesn't work for me though. You're definitely using UDP in your tests? What version of netcat do you have? You're probably on a more recent version. – Chris Davies Nov 11 '18 at 09:01
  • Your first example on TCP/IP does not seem to work on Arch Linux, GNU Netcat, 0.7.1. It hangs. Also, the syntax for nc -l changed since then. – Michaël Oct 21 '20 at 03:45
  • @roaima, UDP only influence the fact that the receiver side knows that the sender side has stopped. However the receiver side is not part of this problem. To stop the receiver, you need -w – Camion Feb 07 '22 at 15:02
  • @Camion yes, except that -w is (or was, back in 2017) ignored in this context – Chris Davies Feb 07 '22 at 16:09
  • @roaima Was it ignored on the receiver side ? – Camion Feb 07 '22 at 16:14
  • 1
    I would have to assume so, because I wrote, "Even here, it's not possible to have the listening netcat time out gracefully. (The -w timeout option is ignored, and -q is irrelevant.)" – Chris Davies Feb 07 '22 at 16:16
  • Oh, sorry, I replied to your comment, without paying attention to the fact that you were th one who wrote the answer – Camion Feb 07 '22 at 16:54
  • No worries, @Camion, there are (at least) two different versions of netcat using slightly different syntax. It may well be that the version I used to create this answer has improved its functionality, or it may be that the "other" version is the dominant one these days – Chris Davies Feb 07 '22 at 16:57
3

udp

# listen on receiver
nc -u -l localhost -p 4300

sender

cat tsmmessage.bin | nc -u -N -q 0 localhost 4300

tcp

# listen on receiver
nc -l localhost -p 4300

sender

cat tsmmessage.bin | nc -N localhost 4300

Edit: This solutions worked for openbsd-netcat for according to the comments, and does not work for GNU Netcat in Archlinux

-1

Stumbled upon this when Googling regarding pretty much the same problem. It turned out the issue was that netcat got killed by bash right after all the data got sucked in, without getting any chance to receive the response.

My solution to this was to add some delay after piping the data, like this:

(echo INFO; sleep 1) | nc redis.service.consul 6379

With a file this can look like:

(cat tsmmessage.bin; sleep 5) | nc -u localhost 4300
Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
-1

A fairly portable option is to send SIGHUP to the client instance of nc. Examples:

kill -1 <pid of nc>

OR

pkill -1 nc

This also works if the data stream was already finished and you need to close the connection cleanly but nc is left running. This can happen in an environment where the closing did not work due to portability issues.