画江湖之 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();
    }
}

生成三个命令

画江湖之 PHP 多进程开发 【通过信号写一个类似nginx services 服务】

画江湖之 PHP 多进程开发 【通过信号写一个类似nginx services 服务】

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!