I promise there is a solution at the end 😛
好的,所以在这里我们是10天后,我相信我已经解决了这个问题.我不想添加一个已经很长的帖子,所以我将在这个答案中包括我尝试的一些事情.
If a child as requested by pid has already exited by the time of the call (a so-called
“zombie” process), the function returns immediately. Any system resources used by the child
are freed…
所以我设置我的pcntl_signal()处理程序这样 –
function sig_handler($signo){
global $childProcesses;
$pid = pcntl_waitpid(-1, $status, WNOHANG);
echo "Sound the alarm! ";
if ($pid != 0){
if (posix_kill($pid, 9)){
echo "Child {$pid} has tragically died!".PHP_EOL;
unset($childProcesses[$pid]);
}
}
}
// These define the signal handling
// pcntl_signal(SIGTERM, "sig_handler");
// pcntl_signal(SIGHUP, "sig_handler");
// pcntl_signal(SIGINT, "sig_handler");
pcntl_signal(SIGCHLD, "sig_handler");
要完成,我将包括我用于分支子进程的实际代码 –
function broadcastData($socketArray, $data){
global $db,$childProcesses;
$pid = pcntl_fork();
if($pid == -1) {
// Something went wrong (handle errors here)
// Log error, email the admin, pull emergency stop, etc...
echo "Could not fork()!!";
} elseif($pid == 0) {
// This part is only executed in the child
foreach($socketArray AS $socket) {
// There's more happening here but the essence is this
socket_write($socket,$msg,strlen($msg));
// TODO : Consider additional forking here for each client.
}
// This is where the signal is fired
exit(0);
}
// If the child process did not exit above, then this code would be
// executed by both parent and child. In my case, the child will
// never reach these commands.
$childProcesses[] = $pid;
// The child process is now occupying the same database
// connection as its parent (in my case mysql). We have to
// reinitialize the parent's DB connection in order to continue using it.
$db = dbEngine::factory(_dbEngine);
}
是的…这是1:1的评论与代码的比例:P
所以这看起来很棒,我看到了回音:
Sound the alarm! Child 12345 has tragically died!
但是当套接字服务器循环是下一次迭代时,socket_select()函数失败会抛出此错误:
PHP Warning: socket_select(): unable to select [4]: Interrupted system call…
服务器现在将完全忘记周围的世界的植物人状态,而不是从根终端手动杀死命令以外的任何请求.
我不会搞清楚为什么会发生这种情况,或者我做了什么来调试它…让我们说这是一个令人沮丧的一周…
很多咖啡,眼睛疼痛,10天后…
鼓卷
TL& DR – 解决方案:
在2007年的php套接字文档和this this教程(搜索“好的育儿”)中提到的here,可以简单地“忽略”从子进程(SIGCHLD)传递SIG_IGN的信号到pcntl_signal( )功能 –
pcntl_signal(SIGCHLD, SIG_IGN);
引用该链接的博文:
If we are ignoring SIGCHLD, the child processes will be reaped automatically upon completion.
相信与否 – 我包括pcntl_signal()行,删除所有其他处理程序和处理孩子的事情,它的工作!没有更多的进程留下来!
在我的情况下,我真的不感兴趣我知道一个子进程何时死亡,或者是谁是,我根本不感兴趣 – 只是他们没有挂起来,我的整个服务器崩溃:P