Hi All,
Was hoping for a little guidance from those who've been there and done that in regards to forking processes and controlling the resulting zombies !.
I have a requirement to implement a daemon on 12+ servers that will listen on a socket for a given notification to do a particular task(move a given file from one server to another). Each server currently handles about 20K requests daily at present using another method, but it is beginning to break under the load. We need this to scale to over 200K / day.
The below code is a cut and paste of various sources on howto's for socket servers, and pcntl. Initial testing seems positive, but all connections to the socket server ( each connection generates a new fork) do not exit nicely, they just zombie. I'm going crazy...and I'm sure its just something simple that someone knowledgeable will point out in a few minutes.
any help is GREATLY appreciated. below is the test code.
<?php
declare(ticks=1);
function sig_handler($signo)
{
syslog(LOG_ALERT, "in sig handler now signo is $signo");
switch ($signo) {
case SIGTERM:
// handle shutdown tasks
exit;
break;
case SIGHUP:
// handle restart tasks
break;
default:
exit();
// handle all other signals
}
}
// setup signal handlers
pcntl_signal(SIGTERM, "sig_handler");
pcntl_signal(SIGHUP, "sig_handler");
$pid = pcntl_fork();
if ($pid == -1) {
die("could not fork");
} else if ($pid) {
exit(); // we are the parent
} else {
// we are the child
}
// detatch from the controlling terminal
if (!posix_setsid()) {
die("could not detach from terminal");
}
/* Turn on implicit output flushing so we see what we're getting
* as it comes in. */
//ob_implicit_flush();
$address = '10.10.10.7';
$port = 10000;
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {
echo "socket_create() failed: reason: " . socket_strerror($sock) . "\n";
}
if (($ret = socket_bind($sock, $address, $port)) < 0) {
echo "socket_bind() failed: reason: " . socket_strerror($ret) . "\n";
}
if (($ret = socket_listen($sock, 5)) < 0) {
echo "socket_listen() failed: reason: " . socket_strerror($ret) . "\n";
}
do {
if (($msgsock = socket_accept($sock)) < 0) {
echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
break;
}
syslog(LOG_ALERT, "incoming connection on port 10000 detected !..forking..");
$subpid = pcntl_fork();
if ($subpid != 0) {
$return = pcntl_waitpid($subpid, $status, WNOHANG);
syslog(LOG_ALERT, "pcntl waitpid of $subpid returned ".$return);
continue;
}
syslog(LOG_ALERT, "forked pid is ".posix_getpid());
/* Send instructions. */
$msg = "\nWelcome to the PHP Test Server. \n" .
"To quit, type 'quit'. To shut down the server type 'shutdown'.\n";
socket_write($msgsock, $msg, strlen($msg));
do {
if (false === ($buf = socket_read($msgsock, 2048, PHP_NORMAL_READ))) {
syslog(LOG_ALERT, "socket_read() failed: reason: " . socket_strerror($ret) . "\n");
break 2;
}
if (!$buf = trim($buf)) {
continue;
}
if ($buf == 'quit') {
break;
}
if ($buf == 'shutdown') {
socket_close($client[$i]['sock']);
break 2;
}
$talkback = "PHP: You said '$buf'.\n";
socket_write($msgsock, $talkback, strlen($talkback));
//echo "$buf\n";
} while (true);
socket_close($msgsock);
syslog(LOG_ALERT, "child now exiting? ");
posix_kill(posix_getpid(), SIGTERM);
} while (true);
socket_close($sock);
?>