php守护进程
守护进程可
- 由系统启动脚本 /etc/rc.local
- crontab任务,
- 用户shell
方式运行
具体概念可参考c的
进程守护化基本步骤
- 1.创建子进程,终止父进程 (pcntl_fork,exit)
- 2.在子进程中创建新会话 (posix_setsid)
- 3.改变工作目录(默认继承了父进程的当前工作目录) (chdir(\’/\’))
- 4.重设文件掩码(默认继承了父进程的) (umask(0) 改变当前的umask为最宽松掩码)
- 5.关闭文件描述符(默认继承了父进程打开的文件描述符) (fclose 关闭已打开的文件描述符)
daemon.php
<?phpecho 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 SID10103 10101 10103 1010310609 10103 10609 1010310610 10609 10609 1010310611 10609 10609 1010310612 10609 10609 10103[root@hkui ~]# ps --pid 10101 -o pid,ppid,pgid,sid PID PPID PGID SID10101 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为一个进程组 10103bash创建的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 SID10564 1 10564 1056410565 10564 10564 1056410566 10564 10564 1056410567 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