php守护进程创建和简要分析

守护进程可

  • 由系统启动脚本 /etc/rc.local
  • crontab任务,
  • 用户shell
    方式运行

具体概念可参考c的

进程守护化基本步骤

  • 1.创建子进程,终止父进程 (pcntl_fork,exit)
  • 2.在子进程中创建新会话 (posix_setsid)
  • 3.改变工作目录(默认继承了父进程的当前工作目录) (chdir('/'))
  • 4.重设文件掩码(默认继承了父进程的) (umask(0) 改变当前的umask为最宽松掩码)
  • 5.关闭文件描述符(默认继承了父进程打开的文件描述符) (fclose 关闭已打开的文件描述符)

daemon.php

<?php
echo posix_getpid().PHP_EOL;

$childs = [];
$worker_num = 3;

//daemon();

for ($i = 0; $i < $worker_num; $i++) {
    fork();
}
while (count($childs)) {
    if (($exit_id = pcntl_wait($status)) > 0) {
        $signo = pcntl_wtermsig($status);

        unset($childs[$exit_id]);
    }
    if (count($childs) < $childs) {
        fork();
    }
}
function daemon()
{
    $pid = pcntl_fork();
    if ($pid < 0) die("fork err");
    if ($pid == 0) {
        if (posix_setsid() <= 0) {
            die("setsid err!");
        }
        if (chdir('/') === false) {
            die("change dir err");
        }
        umask(0);
        fclose(STDIN);
        fclose(STDOUT);
        fclose(STDERR);

    } else {
        exit();
    }
}

function fork()
{
    global $childs;
    $pid = pcntl_fork();
    if ($pid < 0) die("fork err");
    if ($pid == 0) {
        $child_pid = posix_getpid();
        while (true) {
            sleep(10);
        }

    } else {
        $parent_pid = posix_getpid();
        $childs[$pid] = $pid;


    }
}

分析

不执行daeon函数时
[root@hkui ~]# pstree -p|grep php
           |-sshd(3169)-+-sshd(10101)---bash(10103)---php(10609)-+-php(10610)
           |            |                                        |-php(10611)
           |            |                                        `-php(10612)
           



[root@hkui ~]# ps --sid 10103 -o pid,ppid,pgid,sid
  PID  PPID  PGID   SID
10103 10101 10103 10103
10609 10103 10609 10103
10610 10609 10609 10103
10611 10609 10609 10103
10612 10609 10609 10103

[root@hkui ~]# ps --pid 10101 -o pid,ppid,pgid,sid
  PID  PPID  PGID   SID
10101  3169 10101 10101

[root@hkui ~]# ps --pid 3169 -o pid,ppid,pgid,sid
  PID  PPID  PGID   SID
 3169     1  3169  3169

------------------------------------------------------------------------
bash(10103)和它创建的子进程们(10606,10610,10611,10612)属于同一个会话期
sid为bash的进程号,所以bash为创建该会话的首进程
bash为一个进程组 10103
bash创建的php进程为一个进程组 
这两个进程组同属一个会话期

程序daemon.php运行时创建了进程组10609,它即为组长
执行了daemon()
输出
10563

[root@hkui ~]# pstree -p|grep php
           |-php(10564)-+-php(10565)
           |            |-php(10566)
           |            `-php(10567)

[root@hkui ~]# ps --sid 10564 -o pid,ppid,pgid,sid
  PID  PPID  PGID   SID
10564     1 10564 10564
10565 10564 10564 10564
10566 10564 10564 10564
10567 10564 10564 10564


执行了daemon.php后,程序运行起来了,进程id为10563
在10563里fork一次,得到子进程10564,父进程10563退出
子进程10564里执行setsid后发生了主要的以下三件事
    1.10564创建了新的进程组,自己升级为组长
    2.10564创建了新的会话组,并成为该会话组的会话首进程
    3.10564和控制终端失去联系
由于其父进程10563退出,它的父进程变为init进程
在10564里fork了3个子进程,继承了10564的组Id,会话Id

posted @ 2019-05-11 12:12 H&K 阅读(...) 评论(...) 编辑 收藏