Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/249.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 终止从套接字服务器分叉的僵尸子进程 免责声明_Php_Sockets_Child Process - Fatal编程技术网

Php 终止从套接字服务器分叉的僵尸子进程 免责声明

Php 终止从套接字服务器分叉的僵尸子进程 免责声明,php,sockets,child-process,Php,Sockets,Child Process,我很清楚,在这种情况下,PHP可能不是套接字服务器的最佳选择。请不要建议 不同的语言/平台-相信我-我从所有人那里都听到过 方向 在Unix环境中工作并使用PHP5.2.17,我的情况如下-我用PHP构建了一个与flash客户端通信的套接字服务器。我遇到的第一个麻烦是,每个传入连接都会阻塞顺序连接,直到它完成处理。我通过使用PHP的pcntl\u fork()解决了这个问题。我成功地生成了许多子进程(将它们的PID保存在父进程中),这些子进程负责向其他客户端广播消息,从而“释放”父进程并允许它继

我很清楚,在这种情况下,PHP可能不是套接字服务器的最佳选择。请不要建议 不同的语言/平台-相信我-我从所有人那里都听到过 方向

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

我现在的主要问题是处理这些死/僵尸子进程的集合并终止它们。我已经(一遍又一遍地)阅读了相关的PHP手册页面,并意识到父进程负责清理其子进程。当子进程执行退出(0)时,父进程从其子进程接收信号。我可以使用
pcntl\u signal()
函数设置信号处理程序来“捕获”该信号

我的信号处理器如下所示:

declare(ticks=1);
函数sig_处理程序($signo){
全局$forks;//这是一个包含所有子PID的数组
foreach($forks AS$key=>$childPid){
echo“我的孩子{$childPid}走了吗?”;
if(posix_kill($childPid,9)){
echo“Child{$childPid}不幸死亡!”;
未设置($forks[$key]);
}
}
}
我确实看到echo的包括需要删除的相关和正确的子PID,但似乎

posix_kill($childPid, 9)
据我所知,这是kill-9$childPid的同义词,它返回TRUE,尽管它实际上没有删除进程

摘自:

成功时返回TRUE,失败时返回FALSE


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

web5 5296 5234 0 14:51?00:00:00[php]
web5 5321 5234 0 14:51?00:00:00[php]
web5 5466 5234 0 14:52?00:00:00[php]
如您所见,所有这些进程都是父进程的子进程,其PID为
5234

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

我的僵尸启示录计划坚如磐石——
但是,即使是
sudokill-9
也不能杀死僵尸子进程,我到底能做什么呢


10天后更新
如果你还能够忍受我的漫无边际的话,我在做了一些额外的研究后已经自己回答了这个问题

关于您的免责声明-PHP在编写服务器方面并不比许多其他语言好/差。有些事情是不可能做到的(轻量级进程、异步UOS I/O),但这些并不真正适用于分叉服务器。如果您使用的是OO代码,那么一定要确保启用了循环引用检查垃圾收集器

一旦子进程退出,它就会变成僵尸,直到父进程将其清除。您的代码似乎会在收到任何信号时向每个孩子发送一个杀戮信号。它不会清理进程条目。它将终止尚未调用exit的进程。要正确获取子进程,应调用waitpid(另请参见pcntl_wait手册页面上的内容)。

僵尸是死进程。你不能杀死人。所有过程 最终死亡,当他们死亡时,他们变成僵尸。他们消费 几乎没有资源,这是意料之中的,因为它们已经死了! 僵尸的原因是僵尸的父进程可以 检索僵尸的退出状态和资源使用统计信息。这个 父级向操作系统发出信号,表示它不再需要僵尸 通过使用wait()系统调用之一

当一个进程死亡时,它的子进程都成为它的子进程 进程编号1,即init进程。Init是“始终” 等待孩子们死去,这样他们就不会像僵尸一样

如果你有僵尸进程,这意味着那些僵尸还没有被激活 由他们的家长等待(查看ps-l显示的PPID)。你 有三种选择:修复父进程(使其等待);杀死 父母亲或者接受它。记住,和它一起生活并不难 因为僵尸在输出中只占一行多一点的空间 私人秘书长

我保证最后会有一个解决方案:p

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

通过阅读文档和对文档的评论,说明说明如下:

如果pid请求的子项在调用时已退出(所谓的
“僵尸”进程),函数立即返回。子系统使用的任何系统资源
被释放了

因此,我将我的
pcntl\u 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的比率

这看起来很棒,我看到了以下的回音:

拉响警报!12345儿童惨死

但是,当套接字服务器循环执行下一次迭代时,
socket\u select()
pcntl_signal(SIGCHLD, SIG_IGN);