1

I need to test receipt of TCP data. I may not use iperf.

The requirements are saying that I should create a TCP server to which will someone will send random data. I need to count the number of bytes received.

I have been told to use the following:

timeout 60 cat < /dev/tcp/IP_addr/port | wc –c > byte_count-n.txt

Will this do what they think it will? Will it receive data for 60 seconds and then, when the timeout expires, pipe the received data to wc, which will write the total to a disk file?

As a programmer, I would feel happier if it read

(timeout 60 cat < /dev/tcp/IP_addr/port) | wc –c > byte_count-n.txt

But obviously the shell won’t accept that. Am I correct to be worried?

Note that we are using the Ash shell, but there is some concern that only Bash supports /dev/tcp

1 Answers1

3

Note that this answers an earlier version of the question where the command was meant to be a server.

No in bash (and ksh where that feature comes from), /dev/tcp/host/port are virtual files that are meant to be for client TCP connections.

The shell will connect to host:port, and make that connected socket the fd that is the subject of the redirection. With < or <>, it's fd 0 (stdin), with >, >> it's fd 1, but the operators make no difference. In particular it's not because you use < that the shell shuts down the sending direction of the socket; stdin will still be connected to a socket which you can both read from and write to.

If you want to listen (be a server) and accept one or more connections, you can't use /dev/tcp/host/port.

You'd need to use a dedicated tool like socat or nc, or a shell with builtin support for that like zsh with its ztcp builtin.

timeout 60 socat -u tcp-listen:12345,reuseaddr,bind=127.0.0.1,fork - | wc -c

Will listen on port 12345 on the loopback IPv4 address and accept incoming connections in child processes, write what is received on stdout (here piped to wc).

There are several implementations of a tool called nc or netcat with which you can generally do the same with:

timeout 60 nc -l 127.0.0.1 12345 | wc -c

Note that it run that command for 60 seconds. That includes the time while it's sitting doing nothing waiting for incoming connections.

If you want the timer to start upon the incoming connection, you could do instead:

socat -u tcp-listen:12345,reuseaddr,bind=127.0.0.1 'EXEC:timeout 60 cat' | wc -c

Here accepting only one TCP connection (no fork) which is then piped to timeout 60 cat.

Just to clarify what I think you may be asking in the subject, when you do:

 cmd1 | cmd2

It's not cmd1 running and when it's finished, the data is sent to cmd2. Instead cmd1 and cmd2 are started concurrently (they run in parallel) with a pipe in between them (cmd1's stdout is the writing end of the pipe and cmd2's stdin is the reading end).

In:

 timeout 60 nc -l 127.0.0.1 12345 | wc -c

You've got timeout and wc running in parallel. timeout starts another process in which it executes nc (which will share the same stdout).

After 60 seconds, timeout will kill that other process. At that point nc will exit, but it will have written what it has received from the socket to the pipe (nc or socat don't buffer their output), so even if wc hasn't read it yet, it will be accounted for as wc will keep reading until the pipe is empty.

(timeout 60 nc ...) | wc –c

Would be the same. (code) is to start a subshell (a child shell process (in shells other than ksh93) that is evaluating the code). But here, since it's part of pipeline, that code has to be in a subshell already (different parts of a pipeline have to run in different processes as they run concurrently).

  • A fast and detailed response form someone who's reputation indicates that he knows what he is speaking of. I will take this answer to management. – Mawg says reinstate Monica Dec 19 '16 at 10:10
  • Aaaaargh!! I made a *big* mistake. I am suppsed to be a client, not a server. Please accept my apologies. I will update the question. What difference does it make? – Mawg says reinstate Monica Dec 19 '16 at 10:23
  • @Mawg, That's now a very different question, so most of my answer is now irrelevant, but then there's probably enough information in here to show you that yes, it should work as expected provided cat doesn't buffer its output (the GNU implementation doesn't, you can add the -u option for others (ignored by GNU cat)). – Stéphane Chazelas Dec 19 '16 at 11:04
  • My apologies - again :-) I have accepted you answer and reverted the question to its original, so that the question & answer match – Mawg says reinstate Monica Dec 19 '16 at 11:26