画江湖之 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 协议》,转载必须注明作者和本文链接
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

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