畫江湖之 PHP 多程式開發 [透過訊號寫一個類似 nginx services 服務]

Krisji發表於2019-04-02

訊號

  • 訊號只是用來通知某程式發生了什麼事件,並不給該程式傳遞任何資料
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 協議》,轉載必須註明作者和本文連結

相關文章