title: How to detect PHP pfsockopen being closed by remote server?
body: <p>I'm trying to make asynchronous HTTP POST requests from PHP server to an Nginx server. I read this very informative <a href="https://segment.com/blog/how-to-make-async-requests-in-php/" rel="nofollow noreferrer">blog post</a> about the issue, decided to use the technique with <code>pfsockopen</code> function, and imported the <a href="https://github.com/segmentio/analytics-php/blob/master/lib/Segment/Consumer/Socket.php" rel="nofollow noreferrer">code</a> doing this written by the blog author. I include the key sections below:</p>
  
  <pre><code>private function createSocket() {
    if ($this-&gt;socket_failed)
      return false;
    $protocol = $this-&gt;ssl() ? "ssl" : "tcp";
    $host = $this-&gt;options["host"];
    $port = $this-&gt;ssl() ? 443 : 80;
    $timeout = $this-&gt;options["timeout"];
    try {
      # Open our socket to the API Server.
      # Since we're try catch'ing prevent PHP logs.
      $socket = @pfsockopen($protocol . "://" . $host, $port, $errno,
                           $errstr, $timeout);
      # If we couldn't open the socket, handle the error.
      if (false === $socket) {
        ...
        return false;
      }
      return $socket;
    } catch (Exception $e) {
      ...
      return false;
    }
  }
  
  private function makeRequest($socket, $req, $retry = true) {
    $bytes_written = 0;
    $bytes_total = strlen($req);
    $closed = false;
    # Write the request
    while (!$closed &amp;&amp; $bytes_written &lt; $bytes_total) {
      try {
        # Since we're try catch'ing prevent PHP logs.
        $written = @fwrite($socket, substr($req, $bytes_written));
      } catch (Exception $e) {
        ...
        $closed = true;
      }
      if (!isset($written) || !$written) {
        $closed = true;
      } else {
        $bytes_written += $written;
      }
    }
    # If the socket has been closed, attempt to retry a single time.
    if ($closed) {
      fclose($socket);
      if ($retry) {
        $socket = $this-&gt;createSocket();
        if ($socket) return $this-&gt;makeRequest($socket, $req, false);
      }
      return false;
    }
    $success = true;
    ...
    return $success;
  }
  </code></pre>
  
  <p>It mostly works very well, but I'm observing the following problem. Usually, after about 30 seconds of inactivity, when I send a request this way, Nginx responds with a TCP RST (reset) packet, which <a href="https://stackoverflow.com/questions/251243">I read</a> indicates that the socket has been closed on the remote end. I can also see the connection statuses with <code>netstat -na | grep 8080</code> and by that time, the connection PHP -> Nginx is in state <code>CLOSE_WAIT</code>, while Nginx -> PHP is in <code>FIN_WAIT2</code>. <a href="https://kb.iu.edu/d/ajmi" rel="nofollow noreferrer">This guide</a> confirms that this means the remote server wants to close the connection.</p>
  
  <p>I know that the issue is caused by the connection timeout settings on the remote end, because when I increase it, connections shown by <code>netstat</code> remain in state <code>ESTABLISHED</code> for longer, and if PHP server decides to reuse such a connection, it works fine. However, I don't want to set connection timeout to a very high value, as I'm worried of running out of ports.</p>
  
  <p>Is there any way I can detect in PHP that a connection went into a <code>CLOSE_WAIT</code> state? I tried the following and none of it works:</p>
  
  <ul>
  <li>Checking if handle returned by <code>pfsockopen</code> is false.</li>
  <li>Checking <code>$errno</code> variable written by <code>pfsockopen</code>.</li>
  <li>Try-catching exceptions from <code>pfsockopen</code> and <code>fwrite</code>.</li>
  <li>Checking if <code>fwrite($socket)</code> returns false.</li>
  <li>Checking if <code>fflush($socket)</code> returns false.</li>
  <li>Checking <code>stream_get_meta_data($socket)['timed_out']</code>.</li>
  </ul>