画江湖之 PHP 多进程开发 [通过信号写一个类似 nginx services 服务]
信号
- 信号只是用来通知某进程发生了什么事件,并不给该进程传递任何数据
处理方法
1.忽略此信号 大多数信号都可以使用这种方式进行处理 但有两种信号不能忽略,SIGKILL 和 SIGSTOP SIGKILL 和 SIGSTOP 向内核和超级用户提供使进程终止的可靠方法 2.捕捉信号 通知内核在某种信号发生时,调用一个用户函数,执行希望对事件的处理 3.执行系统默认动作 大多数信号的系统默认动作是终止该进程
代码演示
<?php
// 守护进程化
function daemon() {
// 1-1
$pid = pcntl_fork();//
switch ($pid) {
case -1:
die('Create failed');
break;
case 0:
// Child
// 2.
if ( ($sid = posix_setsid()) <= 0 ) {
die("Set sid failed.\n");
}
// 3.
if (chdir('/') === false) {
die("Change dir failed.\n");
}
// 4.
umask(0);
// 5.
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
break;
default:
// Parent
// 1-2
exit;
break;
}
}
// Fork一个进程
function fork() {
global $childs;
$pid = pcntl_fork();
switch ($pid) {
case -1:
die('Create failed');
break;
case 0:
// Child
pcntl_signal(SIGTERM, SIG_IGN, false);//安装一个信号 忽略kill 杀死进程 导致重新执行下面的任务
while (true) {
sleep(5);
}
break;
default:
// Parent
$childs[$pid] = $pid;
break;
}
}
$cmd = ( $_SERVER['argv'][1] ?? '' );
switch ($cmd) {
case 'start':
// 启动
if (file_exists('/tmp/master_pid')) {//如果存在了主进程的进程id
die("Already running\n");
}
break;
case 'reload':
// 重载子进程
$master_pid = file_get_contents('/tmp/master_pid');//得到主进程的进程id
exec("ps --ppid {$master_pid} | awk '/[0-9]/{print $1}' | xargs", $output, $status);//shell 脚本得到这个主进程下的所有的子进程的id
if ($status == 0) {
$childs = explode(' ', current($output));
foreach ($childs as $id) {
posix_kill($id, SIGKILL);//循环杀死子进程
}
}
exit;
break;
case 'stop':
// 停止所有
$master_pid = file_get_contents('/tmp/master_pid');//得到主进程的进程id
exec("ps --ppid {$master_pid} | awk '/[0-9]/{print $1}' | xargs", $output, $status);//shell 脚本得到这个主进程下的所有的子进程的id
posix_kill($master_pid, SIGKILL);//杀死主进程
if ($status == 0) {
$childs = explode(' ', current($output));
foreach ($childs as $id) {
posix_kill($id, SIGKILL);//循环杀死子进程
}
}
while (true) {
if (! posix_kill($master_pid, 0)) {
@unlink('/tmp/master_pid');//把主进程的进程id 文件给杀死
break;
}
}
exit;
break;
default:
die("Please enter command\n");
break;
}
// 守护进程
daemon();
$childs = [];
$count = 3;
// 保存主进程pid
$master_pid = posix_getpid();
file_put_contents('/tmp/master_pid', $master_pid);
// Fork子进程
for ($i = 0; $i < $count; $i++) {
fork();
}
// 监控子进程
while ( count($childs) ) {
if ( ($exit_id = pcntl_wait($status)) > 0 ) {
unset($childs[$exit_id]);
}
if ( count($childs) < 3 ) {
fork();
}
}
生成三个命令
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: