0

I have two applications on two networked Linux machines on the same LAN. One runs a server program which listens for TCP connections on a specified port and when connected, emits (but does not receive) data. A client program on a different machine listens for TCP connections and when connected, expects to receive the data sent by the server (but does not emit any itself).

Until now I have been using either nc server1 30000 | nc client1 29999 or socat -u TCP:server1:30000 TCP:client1:29999, however with either solution once the network connection fails, the process does not end and doesn't automatically re-connect.

Is there an elegant way to do this?

Earlier I was considering multicast; i.e. have the server multicast the data across the network, but that would require one of the above commands on each computer to terminate the data stream and might end up with the same problems.

This connection only transfers a small amount of data; certainly nowhere near enough to saturate bandwidth or CPU.

  • Stupid question: wouldn't it be easier to have one of the endpoints connect to the other, instead of having a middleman to connect them? – ilkkachu Dec 26 '17 at 15:54
  • Both need incoming TCP connections made, the nc/socat thing has to run from somewhere. Running on either of the machines is fine. – Steven Davies Dec 26 '17 at 18:00
2

I think really reliable solution would be to write some small app in C (or python or perl). In general first thing you might check if connect have failed or transfer is taking too long. Second thing is to check how many data you got from server and how long is it taking to send/receive data. And retry if something went wrong.

In bash, you can check if connect have failed or not using nc exit code.

Checking timeout may be tricky in bash depending on your environment restrictions - if can install timeout it should be easy. If not you still can write something in pure bash.

It will be way more controllable if your remote server drops connection after sending data you can check if received takes longer than something.

It might also be easy if you can receive all data first on your intermediate host and connecting client afterwards.

Something like:

loop for some acceptable amount of retries
  connect server
  if connect failed continue
  save data to buffer
  if connection close and not enough data continue
  if timeout happened interrupt and continue
now if we got data do other loop
  connect client
  if connect failed continue
  send buffer
  if timeout happened interrupt and continue (this is only acceptable if your client is OK to receive data multiple times)

How to do above in bash (note - I did not really test all of it, so it may need minor changes):

for ((attempt = 0; attempt < 10; attempt++)); do
  BUFFER=$(timeout 10 nc server1 port1) || continue
  [ ${#BUFFER} -ge 1 ] || continue
  for ((client_attempt = 0; client_attempt < 10; client_attempt++)); do
    echo "$BUFFER" | timeout 10 nc client2 port2 || continue
  done
  break
done
  • Thanks, that's exactly what I was hoping to avoid but I'll accept the answer if nothing cleaner comes along! – Steven Davies Dec 29 '17 at 21:03
1

I ended up using nmap's ncat in a while(true) loop like this:

/bin/bash -c while true; do ncat -i 50s --recv-only remotehost 12345 | ncat -i 50s --send-only localhost 12346; sleep 10; done

After the 50 second timeout each of the processes ends and the while loop will respawn them.

  • Not sure if elegant, but if it matches your need it's good enough. – Kiwy Jan 15 '18 at 10:31

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.