3

Yesterday I asked a question about catting a file over a UDP socket in bash.

The solution we came up was netcat -c -w 1 -v -u -s 127.0.0.1 239.255.0.1 30001 < test.txt. This worked in the sense that it sent the packets, but there's a problem.

The source file isn't strictly a text file. It's actually a binary file -- the content is mostly text, with embedded non-printable characters and no \n lineendings. Instead, the control character ^C (0x03) is used as a line delimiter.

When netcat was sending packets, it would send as much as possible in a single UDP frame. But I want it to send one UDP frame per ^C-delimited mesasge in the source file.

For example, if my file consists of:

foo^Cbar^Cbaz^C

using netcat would result in one UDP frame being sent. What I want is to send 3 messages:

  1. foo^C
  2. bar^C
  3. baz^C

Is there a way to accomplish this?


I have tried a number of possible solutions, but nothing's worked.

For one I've tried sedding the source file to replace the ^C with ^C\n, but that had no effect:

sed 's/^C/^C\n\0/g' test.txt  | netcat -n -vv -c -w 1 -v -u -s 127.0.0.1 239.255.0.2 30002

I also tried catting the files to /dev/udp/ instead of using netcat, but the results were similar.

cat test.txt > /dev/udp/239.255.0.2/30002

Finally I tried using awk to print one line at a time and redirecting that to /dev/udp, but the results were really the same.

It appears that both netcat and cat > /dev/udp both buffer the input until it has a full frame, then sending the frame. That's not what I want.

Can I flush the udp buffer, or some other way send one UDP message per ^C-delimited message in the source file?

4
gawk -v 'RS=\03' -v cmd='
  socat -u - udp-datagram:239.255.0.1:30001,bind=127.0.0.1' '
  {print $0 RT| cmd; close(cmd)}' < file

should work as long as there's not more than 8k in between two ^Cs.

That runs one socat command per record (records being ^C delimited via the record separator variable), with the record plus the record terminator fed to socat via a pipe.

socat reads 8192 bytes at a time, so it's as large a packet it sends can get.

gawk writes to the pipe as a full record per write(2).

Using gawk instead of awk here to make sure it handles NUL bytes properly.

  • Brilliant, this seems to work exactly as I want. Now that I've read about close in gawk's manpage, I think I understand how it's working as well. – John Dibling Jan 31 '14 at 16: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.