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?

1 Answer 1

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.

1
  • 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. Commented Jan 31, 2014 at 16:16

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.