Writing to a socket and handling broken pipes
Asked Answered
P

3

8

I have some code in PHP that connects to a socket. I've been getting a broken pipe intermittently while writing to it. The problems seems to go away if write to the pipe again. I'm wondering what's required (the safest way) to recover from it. I'm also wondering whether socket_write may return without writing the full string that was passed into it. Here's what I have currently.

function getSocket() {
  $socket = socket_create( AF_UNIX, SOCK_STREAM, 0 );
  if ( $socket === FALSE ) {
    throw new Exception(
      "socket_create failed: reason: " . socket_strerror( socket_last_error() ));
    }
  }

  $result = socket_connect($socket, $address);
  if ($result === false) {
    throw new Exception("socket_connect() failed.\nReason: ($result) " .
        socket_strerror(socket_last_error($socket)));
  }
  return $socket;
}

function writeSocket($stmt) {
  $tries = 0;
  $socket = getSocket();
  do {
    // Is is possible that socket_write may not write the full $stmt?
    // Do I need to keep rewriting until it's finished?
    $writeResult = socket_write( $socket, $stmt, strlen( $stmt ) );
    if ($writeResult === FALSE) {
      // Got  a broken pipe, What's the best way to re-establish and 
      // try to write again, do I need to call socket_shutdown?
      socket_close($socket);
      $socket = getSocket();
    }
    $tries++;
  } while ( $tries < MAX_SOCKET_TRIES && $writeResult ===  FALSE);
}
Paperhanger answered 26/8, 2011 at 18:55 Comment(0)
L
2

Q1. I'm wondering what's required (the safest way) to recover from it.

A: That depends on the application. The socket listener is closing the connection, or you've set socket options that you're not showing us. How you deal with either of these things depends on the semantics of the application.

Q2. I'm also wondering whether socket_write may return without writing the full string that was passed into it.

A: Yes. socket_write() can write no bytes, some of the bytes, or all of the bytes before returning. If it returns a value greater than zero but less than the length of the input, you should adjust offsets (perhaps using substr()). If it returns zero or less, inspect socket_last_error() for clues as to whether it is retry-able. This contortion is covered in the manual.

Lattice answered 26/8, 2011 at 23:19 Comment(2)
The only options I'm passing in are what I have in my example. I was told I don't have to worry about socket_write writing fewer characters than instructed to because this is a UNIX domain socket so there is no network delay. Do you agree with that?Paperhanger
The documentation for socket_write() offers no such guarantee.Lattice
F
0

Have you tried setting SO_KEEPALIVE or SO_SNDTIMEO? You might also test in your loop for the buffer length to see if the whole thing has been sent.

Good luck and HTH, -- Joe

Figurative answered 26/8, 2011 at 19:16 Comment(2)
I know I can test the return value of socket_write to see how many bytes were actually written, my question is whether that is actually necessary, most examples I've seen don't attempt to do it. Also, what do you mean that by setting SO_KEEPALIVE and SO_SNDTIMEO I will not get the broken pipe? The pipe is broken because the socket server (not PHP) had a problem. I don't think there's anything on I can do on the PHP client to prevent that.Paperhanger
Warning Message: An error was detected which prevented the loading of this page. If this problem persists, please contact the website administrator. socket_write() [<a href='function.socket-write'>function.socket-write</a>]: unable to write to socket [32]: Broken pipe application/classes/cci/DataSrv.phpPaperhanger
P
0

Use socket_set_nonblock() and fix your while statement:

$writeResult === FALSE should be $writeResult !== FALSE instead.

Particularly answered 26/8, 2011 at 22:54 Comment(1)
Why should I use socket_set_nonblock? Ther's nothing else for the script to do until the socket is read.Paperhanger

© 2022 - 2024 — McMap. All rights reserved.