Reputation: 454
There is a small script that listens to the port. When somebody connected, the process forks.
The problem is that when the child process close, it does not close correctly, but becomes a zombie process.
I also want to add that it is important for me that the script work asynchronously and can support several incoming connections.
How to properly terminate child processes in my case?
Below is the script code:
$serverSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($serverSocket=== false) {
echo 'socket_create() failed: reason: ' . socket_strerror(socket_last_error()) . "\n";
}
if (!socket_bind($serverSocket, $address, $port)) {
echo 'socket_bind() failed: reason: ' . socket_strerror(socket_last_error($serverSocket)) . "\n";
}
if (!socket_listen($serverSocket)) {
echo 'socket_listen() failed: reason: ' . socket_strerror(socket_last_error($serverSocket)) . "\n";
}
do {
$clientSocket = socket_accept($serverSocket);
if ($clientSocket === false) {
echo 'socket_accept() failed: reason: ' . socket_strerror(socket_last_error($serverSocket)) . "\n";
break;
}
$pid = pcntl_fork();
if ($pid === -1) {
die('Can\'t fork process');
}
if ($pid) {
echo "Someone connected $pid \n";
pcntl_waitpid($pid, $status, WNOHANG);
echo "Someone disconnected \n";
} else {
/* Send instructions. */
$msg = "\nWelcome to the brackets analyzer!. \n" .
"Enter a string to analyze. \n" .
"To quit, type 'quit'\n";
socket_write($clientSocket, $msg, strlen($msg));
do {
$buf = socket_read($clientSocket, 2048, PHP_NORMAL_READ);
if ($buf === false) {
echo 'socket_read() failed: reason: ' . socket_strerror(socket_last_error($clientSocket)) . "\n";
break;
}
if (!$buf = trim($buf)) {
continue;
}
if ($buf === 'quit') {
$msg = "Goodbye!\n";
socket_write($clientSocket, $msg, strlen($msg));
exit();
}
$talkback = "PHP: You said '$buf'.\n";
socket_write($clientSocket, $talkback, strlen($talkback));
} while (true);
}
socket_close($clientSocket);
} while (true);
socket_close($serverSocket);
UPD:
I tried to add SIGCHLD
handler by calling pcntl_signal
(full code below).
The problem is that when someone exits the child process, the process ends and becomes a zombie process, but the next connection to the server immediately deletes all zombie processes.
I really don't understand how it works.
How to achieve the child process correctly closed immediately?
declare(ticks = 1);
set_time_limit(0);
/* Turn on implicit output flushing so we see what we're getting
* as it comes in. */
ob_implicit_flush();
declare(ticks = 1);
pcntl_signal(SIGCHLD, function () {
pcntl_waitpid(-1, $status);
echo "Someone disconnected \n";
});
$address = '192.168.0.100';
$port = 7888;
$serverSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($serverSocket=== false) {
echo 'socket_create() failed: reason: ' . socket_strerror(socket_last_error()) . "\n";
}
if (!socket_bind($serverSocket, $address, $port)) {
echo 'socket_bind() failed: reason: ' . socket_strerror(socket_last_error($serverSocket)) . "\n";
}
if (!socket_listen($serverSocket)) {
echo 'socket_listen() failed: reason: ' . socket_strerror(socket_last_error($serverSocket)) . "\n";
}
do {
$clientSocket = socket_accept($serverSocket);
if ($clientSocket === false) {
echo 'socket_accept() failed: reason: ' . socket_strerror(socket_last_error($serverSocket)) . "\n";
break;
}
$pid = pcntl_fork();
if ($pid === -1) {
die('Can\'t fork process');
}
if ($pid) {
echo "Someone connected $pid \n";
} else {
/* Send instructions. */
$msg = "\nWelcome to the brackets analyzer!. \n" .
"Enter a string to analyze. \n" .
"To quit, type 'quit'\n";
socket_write($clientSocket, $msg, strlen($msg));
do {
$buf = socket_read($clientSocket, 2048, PHP_NORMAL_READ);
if ($buf === false) {
echo 'socket_read() failed: reason: ' . socket_strerror(socket_last_error($clientSocket)) . "\n";
break;
}
if (!$buf = trim($buf)) {
continue;
}
if ($buf === 'quit') {
$msg = "Goodbye!\n";
socket_write($clientSocket, $msg, strlen($msg));
exit();
}
$talkback = "PHP: You said '$buf'.\n";
socket_write($clientSocket, $talkback, strlen($talkback));
} while (true);
}
socket_close($clientSocket);
} while (true);
socket_close($serverSocket);
Upvotes: 0
Views: 233