Home » Php » php – Writing to a socket and handling broken pipes

php – Writing to a socket and handling broken pipes

Posted by: admin July 12, 2020 Leave a comment

Questions:

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);
}
How to&Answers:

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.

Answer:

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

Answer:

Use socket_set_nonblock() and fix your while statement:

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