Hi folks, I am battling around with socket_select() for some months now and still have an unsolved problem with random hanging.
PHP: 4.3.4 with -sockets, -sigchild, -pcntl and some other things OS: FreeBSD 5.0 (same problem with 4.8 and 5.1) In simple words, I have a server-daemon (runs with PHP4.3.4 now) wich uses socket_select() for accepting new connections and dealing with existing ones. It is an IRC-like chatserver talking with PHP-script running on a webserver on _the same_ machine, same IP, long connects for output, short connects for input. For debugging I use normal TCP-sockets, not unix-domain-sockets. The select runs on all connected sockets for read and error, write is untouched. In testing-enviroment everything works perfect, but in production-eviroment the server hangs after some time. Some facts: - in testing, even 32.000 fast connects (made synchronous with 16 processes) couldn't get the server to hang, in production it hangs after about 3000 - 7000 connects, regardless of low CPU-load - debug-outputs to console before and after the select show clearly the socket_select() is hanging - tried both blocking and non-blocking select, same effect in both cases - both test and production are on the same machine, same PHP - both are getting only local connects from other PHP-scripts - socket-dumps before the select show all sockets in normal state, even if directly before a hang - select hangs sometimes with about 80 synchronous connections, sometimes with only about 20 I thought it might be a bug in PHPs socket-extension, because the hangups come random, indipendent of number of synchronous connects, number of processed connects, id of hightest socket-descriptor, used CPU-time. Maybe i just forgot something, but it doesn't go into my head why it hangs exactly during the select :-/ The code should be okay, it is basically indentical to an example posted some time ago in the php-dev-mailinglist (i've pasted it below). #!/usr/local/bin/php -q <?php set_time_limit(0); // defaults... define('MAXLINE', 1024); // how much to read from a socket at a time define('LISTENQ', 10); // listening queue define('PORT', 10000); // the default port to run on define('FD_SETSIZE', 5); // file descriptor set size (max number of concurrent clients)... // for kill the biatch... function killDaemon() { global $listenfd, $client; socket_close($listenfd); $msg = "Daemon going down!\n"; for ($i = 0; $i < FD_SETSIZE; $i++) { if ($client[$i] != null) { socket_write($client[$i], $msg, strlen($msg)); socket_close($client[$i]); } } print "Shutting down the daemon\n"; exit; } // whenever a client disconnects... function closeClient($i) { global $client, $remote_host, $remote_port; print "closing client[$i] ({$remote_host[$i]}:{$remote_port[$i]})\n"; socket_close($client[$i]); $client[$i] = null; unset($remote_host[$i]); unset($remote_port[$i]); } // set up the file descriptors and sockets... // $listenfd only listens for a connection, it doesn't handle anything // but initial connections, after which the $client array takes over... $listenfd = socket_create(AF_INET, SOCK_STREAM, 0); if ($listenfd) print "Listening on port " . PORT . "\n"; else die("AIEE -- socket died!\n"); socket_setopt($listenfd, SOL_SOCKET, SO_REUSEADDR, 1); if (!socket_bind($listenfd, "0.0.0.0", PORT)) { socket_close($listenfd); die("AIEE -- Couldn't bind!\n"); } socket_listen($listenfd, LISTENQ); // set up our clients. After listenfd receives a connection, // the connection is handed off to a $client[]. $maxi is the // set to the highest client being used, which is somewhat // unnecessary, but it saves us from checking each and every client // if only, say, the first two are being used. $maxi = -1; for ($i = 0; $i < FD_SETSIZE; $i++) $client[$i] = null; // the main loop. while(1) { $rfds[0] = $listenfd; for ($i = 0; $i < FD_SETSIZE; $i++) { if ($client[$i] != null) $rfds[$i + 1] = $client[$i]; } // block indefinitely until we receive a connection... $nready = socket_select($rfds, $null, $null, null); // if we have a new connection, stick it in the $client array, if (in_array($listenfd, $rfds)) { print "listenfd heard something, setting up new client\n"; for ($i = 0; $i < FD_SETSIZE; $i++) { if ($client[$i] == null) { $client[$i] = socket_accept($listenfd); socket_setopt($client[$i], SOL_SOCKET, SO_REUSEADDR, 1); socket_getpeername($client[$i], $remote_host[$i], $remote_port[$i]); print "Accepted {$remote_host[$i]}:{$remote_port[$i]} as client[$i]\n"; break; } if ($i == FD_SETSIZE - 1) { trigger_error("too many clients", E_USER_ERROR); exit; } } if ($i > $maxi) $maxi = $i; if (--$nready <= 0) continue; } // check the clients for incoming data. for ($i = 0; $i <= $maxi; $i++) { if ($client[$i] == null) continue; if (in_array($client[$i], $rfds)) { $n = trim(socket_read($client[$i], MAXLINE)); if (!$n) closeClient($i); else { // if a client has sent some data, do one of these: if ($n == "/killme") killDaemon(); else if ($n == "/quit") closeClient($i); else { // print something on the server, then echo the incoming // data to all of the clients in the $client array. print "From {$remote_host[$i]}:{$remote_port[$i]}, client[$i]: $n\n"; for ($j = 0; $j <= $maxi; $j++) { if ($client[$j] != null) socket_write($client[$j], "From client[$i]: $n\r\n"); } } } if (--$nready <= 0) break; } } } ?> thanks for help, Thomas 'Neo' Weber --- [EMAIL PROTECTED] [EMAIL PROTECTED] -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php