Linux – Scripted write-then-read from Unix domain socket using socat

linuxpipesocket

I have a simple server listening on a Unix domain socket (on a CentOS box in case that's important). When I send the command "DATE" to the socket it writes back a welcome message and then "APRIL 15 2015". I can do this manually using the command:

socat - UNIX-CONNECT:/tmp/server.sock

but I now want to script it. I can send my DATE command to the socket by piping the output of echo to the above, but then socat returns with only the welcome message. I'm not sure if socat is returning just the first 2 lines, or waiting for a quiet period before closing the socket, or what. eg:

echo "DATE" | socat - UNIX-CONNECT:/tmp/server.sock

How can I make socat capture the whole response before disconnecting? I've tried -t and -T parameters to make it wait 5 seconds but that has no effect, socat returns immediately.

Best Answer

In:

echo "DATE" | socat - UNIX-CONNECT:/tmp/server.sock

echo writes echo\n then exits which closes the writing end of the pipe.

That results on eof being seen on the reading side of the - address. Then socat shuts down the "sending" end of the unix domain socket and terminates as long as it's not seen anything coming in from the other direction from the socket within 0.5 seconds.

That 0.5 second timeout can be increased with the -t option. So with:

echo DATE | socat -t 300 - UNIX-CONNECT:/tmp/server.sock

socat would wait 5 minutes for the date reply or the server to shutdown the sending side of its connection whichever comes first.

If your server aborts when its clients shuts down its sending side, you could instead keep your client (left side of the pipe: echo) running until the server terminates the connection (assuming it shuts down the connection straight after sending its reply) which you could do with something like:

sh -c 'echo "$$"; echo DATA; exec sleep infinity' | {
  IFS= read -r pid
  socat -t0 - UNIX-CONNECT:/tmp/server.sock
  kill -s PIPE "$pid" # terminate the client after the server shuts down
}

Or:

echo DATE | socat -t0 -,ignoreeof UNIX-CONNECT:/tmp/server.sock

(with ignoreeof, socat ignores eof and keeps trying to read more every second. For a pipe, nothing can ever come after eof, but that still gives us what we want: simulate a client that is still there).

Or terminate as soon as it has seen the reply:

sh -c 'echo "$$"; echo DATA; exec sleep infinity' | {
  IFS= read -r pid
  socat -t0 - UNIX-CONNECT:/tmp/server.sock | {
    IFS= read -r welcome
    IFS= read -r date
    printf '%s\n' "$date"
  }
  kill -s PIPE "$pid" # terminate the client after the reply has been read
}
Related Question