title: PHP: how to use socket_select() and socket_read() properly
body: <p><em><strong>Edit:</em></strong> *Bug in test harness was causing me to misinterpret the results. <code>socket_select()</code> works <strong><em>exactly</em></strong> as you might expect: it really does wait until there is data ready on the socket. But it will report ready if you call it after the client closes the connection. Turns out it's all my fault, but I'll leave the question here in case anyone else ever suspects the behavior of <code>socket_select()</code>.</p>
  
  <p>I have a multi-threaded PHP application and I'm using sockets to communicate between the threads. The communication works pretty well, but I end up doing a lot of unnecessary reading of sockets that have no data ready. Perhaps there's something about socket programming that I'm missing.</p>
  
  <p>The <a href="http://www.php.net/manual/en/function.socket-select.php" rel="nofollow">PHP doc</a> for <code>socket_select()</code> says <em>The sockets listed in the <code>read</code> array will be watched to see if a read will not block</em>.</p>
  
  <p>This is exactly the behavior I want: call <code>socket_select()</code> to wait until one of my child threads is trying to talk to me. But that only works for the very first time the thread writes, after I've accepted the connection. After that, <code>socket_select()</code> will forever say that the socket is ready, even after I've read all the data from it.</p>
  
  <p>Is there some way I can mark that socket 'unready' so <code>socket_select()</code> won't report that it's ready until more data arrives? Or is it conventional to close that connection after I've read all the data, and await another connection request? I've done a lot of tutorial- and explanation-reading, but I haven't been able to figure out how to do this correctly. Maybe I'm missing something obvious?</p>
  
  <p>In case it helps to see code, here's what I'm doing:</p>
  
  <pre><code>// Server side setup in the main thread
  $this-&gt;mConnectionSocket = socket_create(AF_INET, SOCK_STREAM, 0);
  
  $arrOpt = array('l_onoff' =&gt; 1, 'l_linger' =&gt; 0);
  @socket_set_option($this-&gt;mConnectionSocket, SOL_SOCKET, SO_LINGER, $arrOpt);
  @socket_set_option($this-&gt;mConnectionSocket, SOL_SOCKET, SO_REUSEADDR, true);
  @socket_bind($this-&gt;mConnectionSocket, Hostname, $this-&gt;mPortNumber);
  @socket_listen($this-&gt;mConnectionSocket);
  @socket_set_block($this-&gt;mConnectionSocket);
  .
  .
  .
  // Then call listen(), which looks like this:
      public function listen(&amp;$outReadySockets) {
          $null = null;
  
          while(true) {
              $readyArray = array_merge(array($this-&gt;mConnectionSocket), $this-&gt;mReceiverSockets);
              socket_select($readyArray, $null, $null, $waitTime = null);
  
              if(in_array($this-&gt;mConnectionSocket, $readyArray) === true) {
                  $this-&gt;acceptConnection();
                  $key = array_search($this-&gt;mConnectionSocket, $readyArray);
  
                  if($key === false) {
                      throw new IPCException("array_search() returned unexpected value");
                  } else {
                      unset($readyArray[$key]);
                      if(in_array($this-&gt;mConnectionSocket, $readyArray) === true) {
                          throw new IPCException("in_array() says the key is still there");
                      }
                  }
              }
  
              if(count($readyArray) &gt; 0) {
                  $outReadySockets = array_merge($readyArray);
                  break;
              }
          }
      }
  
  
  // Client side setup in the child thread
  $this-&gt;mSocket = @socket_create(AF_INET, SOCK_STREAM, 0);
  @socket_set_block($this-&gt;mSocket);
  @socket_connect($this-&gt;mSocket, Hostname, $this-&gt;mPortNumber);
  .
  .
  .
  @socket_write($this-&gt;mSocket, $inDataToWrite, $lengthToWrite);
  
  
  
  // Main thread reads the socket until it's empty
      $data = "";
      $totalBytesRead = 0;
      while($totalBytesRead &lt; $inNumberOfBytesToRead) {
          // Strange that even if we set the socket to block mode, socket_read()
          // will not block. If there's nothing there, it will just return an
          // empty string. This is documented in the PHP docs.
          $tdata = socket_read($inSock, $inNumberOfBytesToRead);
          if($tdata === false) {
              throw new IPCException("socket_read() failed: " . socket_strerror(socket_last_error()));
          } else {
              $data .= $tdata;
  
              $bytesReadThisPass = strlen($tdata);
              if($bytesReadThisPass === 0) {
                  break;
              }
          }
  
          $totalBytesRead += $bytesReadThisPass;
      }
  .
  .
  .
  // Then calls listen() again
  </code></pre>
  
  <p>As I say, it works great, except that when I call <code>listen()</code> a second time, it tells me that the socket is still ready. That seems to be what the PHP doc is saying, but I don't want that. I want to know when there really is data there. Am I doing it wrong? Or just missing the point?</p>