I have a PHP script that needs to contact another server for information about something.
I'm currently using SSH (via ControlMaster auto) for this, which works correctly.

However, the problem is the latency is too high -- simply shell_exec'ing ssh example.com takes 80 milliseconds, which is far higher than the actual latency between the servers (0.2 ms, as they're connected by an Ethernet cable).

So now I'm thinking about simply passing data through the existing SSH connection rather than trying to multiplex a new SSH connection into an existing one.

However, I'm not sure how to go about this. What's the best way to pass data into the stdin of an existing SSH connection to example.com and then read the resulting output from its stdout?
(BASH solution is fine here -- I don't need anything PHP-specific.)

  • 1
    Handwaving here: It would possibly involve setting up an SSH tunnel for a particular pair of ports locally and remotely, and having a program listen on the other side. – Kusalananda Sep 23 '17 at 20:32
  • @Kusalananda: I was considering that too, but it requires taking up a fixed port number on the second server which seems unnecessary (and potentially error-prone, if the port is in use) given there's already a connection between the servers? I'm also not sure what the latency would be, though hopefully it'd match that of SSH... – Mehrdad Sep 23 '17 at 20:39
  • 1
    @Mehrdad Unix-domain sockets can also be forwarded over the connection, so you don't need to use up a port. – derobert Sep 23 '17 at 23:22
  • @derobert: I wasn't aware of that. Do you have a link to a quick example so I could see if it might solve my problem? – Mehrdad Sep 24 '17 at 0:34
  • @derobert: Actually never mind, I just looked it up... this might work, I'll have to give it a try. Thanks for the suggestion. – Mehrdad Sep 24 '17 at 1:55

If you're using ControlMaster auto you're already reusing the existing TCP connection, but TCP connection establishment is very fast anyway.

The 80ms delay is likely introduced by a combination of:

  1. php shell_exec starting a new shell (try exec?)
  2. the additional overhead of setting up the new ssh channel over the existing connection
  3. Executing your command on the remote server over your new ssh channel

If you need faster responses, first measure each of these individually, then work to reduce the latency in the part that is slow. If you find out that #2 is slowing you down as you suspect, you can try sending your commands over an existing permanent ssh channel, possibly via a named pipe with your remote command in a read-while loop (the caveats raised by @symcbean will apply).

Something like this

mkfifo /tmp/f_in
mkfifo /tmp/f_out
tail -f /tmp/f_in | ssh user@example.com 'bash -c "while read name; do echo hello \$name; done"' > /tmp/f_out &
time response=$(head -n 1 /tmp/f_out & echo dwurf > /tmp/f_in); echo $response

None of this will ever be as fast as creating a network service that you can query for information. I also expect it would be pretty unreliable.

  • +1 thanks, this seems to be what I want. However, it seems to only work the first time? Mine hangs after the first request for some reason. – Mehrdad Sep 26 '17 at 9:11
  • Hmm, it works for me multiple times. If you don't use tail -f the connection will close after the first run. Is that what's happening to you? – dwurf Sep 27 '17 at 23:59
  • Nope it just hangs. But it may be an artifact that I'm SSHing from MSYS2 (Windows), not Linux? Will have to take a look at it on Linux when I get the chance. – Mehrdad Sep 28 '17 at 0:14

If you had a "static" ssh connection in place, how would an instance of a php script bind to it in order to use it?

Very soon we start talking about locking semantics (difficult to implement in php). Then there's the problem of scaling. Your current solution will scale really well as each ssh connection is discrete.

I'm assuming for now that you control the code running on both boxes. If the reason you are using ssh is because the ssh server is running some proprietary code, then this eliminates a lot of patterns for the solution.

If they are connected via ethernet then should we assume that the network is trusted? Why not use something like rsh?

Is privilege seperation between the client and server important?

This smells like an XY problem.

The only practical solutions here are:

1) to write a server to run at the ssh client end which maintains the open ssh connection and to timeshare its access to clients connecting from localhost without the overhead of ssh. This is not trivial and will not scale.

2) implement a client and server using a low latency protocol and any associated authentication / integrity / confidentiality. This also is not trivial. And you omitted to tell us both how and why you are currently using ssh.

  • Scaling is most definitely not an issue since this is a private server meant to be used by myself and maybe by 1-2 other people at most. I don't think locking will be an issue either -- I'm completely fine with random interleavings (again, just 2-3 users). The internal network is trusted but privilege separation is still important since the servers are accessible from the internet, and I really don't want someone who might hack one server to be able to access the other. (The SSH connection is restricted to running 1 very specific command and has login disabled for that user.) – Mehrdad Sep 24 '17 at 0:32

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.