gpt4 book ai didi

php - 终止从套接字服务器派生的僵尸子进程

转载 作者:IT王子 更新时间:2023-10-29 00:12:03 26 4
gpt4 key购买 nike

Disclaimer

I am well aware that PHP might not have been the best choice in this case for a socket server. Please refrain from suggesting different languages/platforms - believe me - I've heard it from all directions.

Unix 环境 中工作并使用 PHP 5.2.17,我的情况如下 - 我用 PHP 构建了一个与 flash 客户端通信的套接字服务器。我的第一个障碍是每个传入连接都会阻塞顺序连接,直到它完成处理。我通过使用 PHP 的 pcntl_fork()解决了这个问题。我成功地产生了许多子进程(将它们的 PID 保存在父进程中),这些子进程负责向其他客户端广播消息,因此“释放”父进程并允许它继续处理下一个连接[s]。

我现在的主要问题是处理/处理这些死亡/僵尸子进程的集合并终止它们。我已经(一遍又一遍地)阅读了 pcntl_fork() 的相关 PHP 手册页。并意识到父进程负责清理其子进程。当子进程执行 exit(0) 时,父进程会收到来自其子进程的 SIGNAL。我能够使用 pcntl_signal() 函数“捕获”该信号以设置一个信号处理程序

我的 signal_handler 看起来像这样:

declare(ticks = 1); 
function sig_handler($signo){
global $forks; // this is an array that holds all the child PID's
foreach($forks AS $key=>$childPid){
echo "has my child {$childPid} gone away?".PHP_EOL;
if (posix_kill($childPid, 9)){
echo "Child {$childPid} has tragically died!".PHP_EOL;
unset($forks[$key]);
}
}
}

我确实看到了两个 echo ,包括需要删除的相关且正确的子 PID,但似乎

posix_kill($childPid, 9)

我理解为 kill -9 $childPid 的同义词正在返回 TRUE,尽管它实际上并没有删除进程...

取自man pages of posix_kill :

Returns TRUE on success or FALSE on failure.


我正在使用 ps 命令监视子进程。它们在系统上显示如下:

web5      5296  5234  0 14:51 ?        00:00:00 [php] <defunct>
web5 5321 5234 0 14:51 ? 00:00:00 [php] <defunct>
web5 5466 5234 0 14:52 ? 00:00:00 [php] <defunct>

如您所见,所有这些进程都是 PID 为 5234

的父进程的子进程

我是不是遗漏了什么?我似乎已经设法让一切正常工作(确实如此),但我的系统上留下了无数的僵尸进程!

我的僵尸末日计划坚如磐石 -
但是即使 sudo kill -9 也没有杀死僵尸子进程,我到底能做什么呢?


10天后更新

这个问题我已经自己研究过了,如果你还受得了我的唠叨proceed at will .

最佳答案

I promise there is a solution at the end :P

好吧……10 天后,我们到了,我相信我已经解决了这个问题。我不想在已经很长的帖子上添加内容,所以我将在这个答案中包含一些我尝试过的东西。

服用 @sym's advice ,并阅读更多文档和对文档的评论 pcntl_waitpid() 描述状态:

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");

为了完成,我将包括我用于 fork 子进程的实际代码 -

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

所以这看起来很棒,我看到了以下的 echo :

Sound the alarm! Child 12345 has tragically died!

然而,当套接字服务器循环执行下一次迭代时,socket_select()函数抛出此错误失败:

PHP Warning: socket_select(): unable to select [4]: Interrupted system call...

服务器现在会挂起,除了来自根终端的手动终止命令之外,不会响应任何请求。


我不打算解释为什么会发生这种情况,或者我在那之后做了什么来调试它……只能说这是令人沮丧的一周……

喝了很多咖啡,眼睛酸痛,10 天后......

请敲鼓

TL&DR - 解决方案:

提到here在 2007 年 php 套接字文档和 this 中的评论中关于 stuporglue 的教程(搜索“good parenting”),可以通过传递 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()线,删除所有其他处理程序和处理 child 的事情并且它有效!没有了 <defunct>进程悬而未决!

就我而言,我真的没有兴趣确切地知道子进程何时死亡,或者它是谁,我对它们根本不感兴趣 - 只是它们不会闲逛并使我的整个服务器崩溃:P

关于php - 终止从套接字服务器派生的僵尸子进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9976441/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com