在PHP中使用fsockopen()和fgets()时,while()循环如何不停顿?

This is the basic connection code for a small PHP IRC bot. The problem is that it seems that the while() loop does not progress beyond fgets() until it receives data from the IRC server. I want the while() loop to iterate regardless if the IRC server has not yet sent data. Is this possible?

$socket = fsockopen($config['irc_server'], $config['port']);
while (1) 
{
    $data = fgets($socket, 128);
    echo '[RECEIVE] ' . $data;
    $recv = explode(' ', $data);

    if ($recv[0] == 'PING')
    {
        send('PONG', $recv[1]);
    }
}

The problem is that it seems that the while() loop does not progress beyond fgets() until it receives data from the IRC server.

I don't see how that's a problem. What do you want that code to do if it receives nothing?

At the moment, it'll just loop around back to the fgets again, so you're just burning cycles busy-waiting for no good reason. Blocking is the correct behaviour in this instance.

Take a look at ftell. Here is a related example from the php documentation:

#!/usr/bin/php4 -q
<?
#following will hang if nothing is piped:
#$sometext = fgets(STDIN, 256)

$tell = ftell(STDIN);

if (is_integer($tell)==true) 
  {echo "Something was piped: ".fread(STDIN,256)."
";}
else 
  {echo "Nothing was piped
";}

?>

stream_select() can tell if data is available for reading on the socket. But fgets() doesn't return until there's a line break or the stream ends. So you'd have to use fread() instead and split the data yourself.

btw: You might also be interested in the PEAR::Net_SmartIRC package.

Check out the socket_* functions including this one:

socket_set_nonblock

You can can also pass a non-block flag to socket_recv

Here is the obligatory quick and dirty example (no error checking)

/* Create a TCP/IP socket. */
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$result = socket_connect($socket, $address, $service_port);
while (false === ($bytes = socket_recv($socket, $buf, 2048, MSG_DONTWAIT))) 
{ /* do stuff while waiting for data */ }