0

I want to send a file to a TCP server, keep the TCP connection open, wait (couple of seconds) for the response, and send the response to stdout. I don't want the connection to be (half) closed immediately on EOF.

I tried netcat with -q like: nc -q 2 192.168.xxx.xxx 1234 < file.bin but netcat immediately closes the connection after EOF (and the server then closes as well).

I tried socat: socat -T 2 -u FILE:file.bin,ignoreeof tcp:192.168.xxx.xxx:1234 but in unidirectional mode the response is ignored, in bidirectional mode the response is appended to the file.

6
  • Network programming in a shell is next to impossible, due to the difficulty of handling asynchronous events, and the binary nature of packets. Use a language that supports asynchronous binary network traffic (C, Perl, Rust, etc). Commented Nov 13 at 0:52
  • And for something like this, use an expect library for, e.g., perl or python. or even the original tcl expect. This is exactly the kind of thing that expect and friends are for: open a connection to something, wait for a short time or for a known prompt, send whatever, wait for a response & do something with it. They're often used to wait for and respond to login and password prompts, but aren' limited to that. One other alternative if your tcp server on port 1234 uses some well-known protocol, there's a small chance that perl has a library that speaks it. And python might too. Commented Nov 13 at 2:01
  • 1
    @cas: commandline expect -- at least -- connects to a process/program that does I/O over a TTY (by giving it a PTY instead); a socket isn't a TTY and isn't even a first-class file although some shells, and gawk, make it partly work like one Commented Nov 13 at 7:17
  • What do you mean by "response"? Something sent over the TCP connection by the application receiving the file at the other end? The TCP FIN received from the other end? The TCP ACK received for the last data packet that was sent? Commented Nov 13 at 7:25
  • If you don't half-close the connection after having sent the file, how is the other end to know when the file has been transferred fully? Does it know in advance the size of the file it is to receive? Commented Nov 13 at 7:26

2 Answers 2

1

If you don't close the writing end of the connection and keep it fully open, then, unless the server knows in advance the size of the file it is to receive (or that size, or information as to where the file ends, is somehow embedded in the contents of the file), it will have no way to know where the end of the file is.

The default modus operandi of socat is upon eof on the first address to shut the writing side of the other address down (so the other end knows you've finished sending), wait for the -t timeout for the other end to close and then terminate, which is likely what you want here, increasing the timeout to the maximum time you're willing to wait for that answer. So:

socat -t3600 -<file.bin tcp:server:1234

Using - (short for STDIO) which means stdin (here redirected to file.bin) is sent and the server's response goes to stdout, and waiting for up to one hour for the response.

You can test with localhost as the server by running:

socat -t3600 tcp-listen:1234,fork,reuseaddr 'system:"
  cat > file.out || exit; sleep 5; echo OK"'

For the server part in another terminal.

Then:

$ time socat -t3600 -<file.in tcp:localhost:1234
OK
socat -t3600 - tcp:localhost:1234 < file.in  0.00s user 0.01s system 0% cpu 5.012 total

Got the expected OK response after 5 seconds, the time it took for the server to send it (here arbitrarily delayed with that sleep 5 for demonstration).

Note that it does not guarantee that if you get a OK, the file has been correctly sent, without alteration, in full and to the right machine. For that, you'd need a protocol that gives those guarantees such as ssh:

if <file.in ssh hostname 'cat > file.out && echo OK'; then
  echo the file has been successfully received
fi

Using a compressor with its own integrity check can even improve it on the off chance that some glitch in the ssh protocol handling causes the file not to be fully sent while the response manages somehow to make it back to the client:

if <file.in gzip | ssh hostname 'gunzip > file.out && echo OK'; then
  echo the file has been successfully received
fi

(note the echo OK is not even necessary (and ignored anyway here) as ssh transmits the exit status of the command back, which is what we rely on here).

1

Per the man page:

  socat STDIO TCP:$addr:$port,shut-none <$input 

(or other stdin redirection like << <<< something| if desired)

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.