|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2002-12-01 07:59 UTC] polone at townnews dot com
The socket_accept() function doesn't appear to handle kernel level system interrupts. This is a problem because PHP scripts written to use pcntl_signal() won't be executed while socket_accept() is in blocking mode. THAT is a problem because the script can't be killed with:
kill -s SIGUSR1 [pid]
and can't reap zombie processes when SIGCHLD is given (not that is much of a problem on Linux, since you can use SIG_IGN).
A workaround I've made is to set a socket to non-blocking mode:
socket_set_nonblock($hSocket);
And then use a while loop like so:
while (($hClient = @socket_accept($hSocket)) === false) {
// If this is a real error, we need to handle it. Unfortunately, in this
// event we just die() essentially.
if (!is_resource($hSocket)) {
error_log(socket_strerror(socket_last_error($hSocket)));
exit;
}
// We need to sleep for one second so that CPU isn't absorbed with this
// process. This may seem clunky, but select() doesn't appear to work
// correctly with accept() in PHP in blocking mode (that is EINTR does
// not appear to work correctly), thus preventing signals from being
// received. This, in effect, makes the process unkillable. This is the
// workaround, for the moment.
sleep(1);
}
While this works, it would be much better if it just returned when a system interrupt is given like the C-equivalent does. This works because the system can't receive messages from the kernel because it isn't blocking.
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Fri Nov 21 05:00:01 2025 UTC |
Hello, The issue still exists, PHP Version => 4.4.6 System => Linux pentium2.antoine 2.6.20 #5 Sun Feb 18 16:28:17 CET 2007 i686 Build Date => Mar 6 2007 21:15:38 Complete code to reproduce error : script.php ------------------------------------------------------------------ #!/usr/local/bin/php <?php define ( 'BIND_PORT', 3333 ); /* Signal Handler */ function signalHandler( $sig ) { switch ( $sig ) { case SIGTERM : exit( 0 ); break; case SIGCHLD : pcntl_waitpid(-1,$status,WNOHANG); break; } } print "My PID is ".posix_getpid()."\n"; declare ( ticks = 1 ); pcntl_signal( SIGTERM, 'signalHandler' ); pcntl_signal( SIGCHLD, 'signalHandler' ); // infinite execution time set_time_limit( 0 ); // Socket creation $sock = socket_create ( AF_INET, SOCK_STREAM, SOL_TCP ); // Bind sur le port BIND_PORT if ( !socket_bind( $sock, '0.0.0.0', BIND_PORT ) ) { print "Unable to bind to port " . BIND_PORT . " !\n"; exit( 1 ); } // Listening up to 16 buffets socket_listen ( $sock, 16 ); // Infinite loop while ( true ) { // Wait for incoming connections, hangs signal handling $subsock = socket_accept ( $sock ); // Connection received, forking sub-process $subPid = pcntl_fork(); if ( $subPid === 0 ) { // Get remote informations socket_getpeername( $subsock , $remoteAddr , $remotePort ); socket_write( $subsock, 'Simple Socket Server accepting commands from ' . $remoteAddr . "\n" ); // Whe are in interactive mode while ( true ) { $received = socket_read ( $subsock, 65536, PHP_NORMAL_READ ); // Clean shutdown if ( !$received ) { socket_shutdown( $subsock, 2 ); socket_close( $subsock ); exit( 0 ); } // Cleaning entry $received = trim( $received ); if ( $received ) { // two commands : HELLO and QUIT switch ( $received ) { case 'HELLO': socket_write( $subsock, 'HELLO ' . $remoteAddr . "\n" ); break; case 'QUIT': // (shutdown) socket_write( $subsock, 'BYE' . "\n" ); socket_shutdown( $subsock, 2 ); socket_close( $subsock ); exit( 0 ); break; default : socket_write( $subsock, 'Unknown command...' . "\n" ); } } } } } // while ?> ------------------------------------------------------------------ Commands : [Shell1]$ ./script.php My PID is 18135 [Shell2]$ kill 18135 <Happens nothing on Shell1...> [Shell2]$ telnet localhost 3333 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Connection closed by foreign host [Shell1] : The script exits. => The signal is properly intercepted but the handler is only called when the script continues after socket_accept(). Whe are using a little more complex code when the fist process is a child of a fork itself : At this time, the only way to end it is a not very clean SIGKILL. Regards, AB