PHP进程守护和开机自启

PHP守护进程的方式

借助nohup 和& 配合使用(验证OK)

在命令后面加上&符合,可以让启动的进程转到后台运行,而不占用控制台,控制台还可以再运行其它的命令。示例如下:

 While(true){

 echotime().PHP_EOL;

 sleep(3);

}

用&方式来启动该进程

Php deadloop.php &

查看该进程状态

Ps aux | grep

这时我们可以通过fg命令让进程恢复到普通占用控制台的模式

Fg

在命令之前加上nohup ,启动的进程将会忽略linux的挂起信号 (SIGHUP),

那什么情况下会触发linux下SIGHUP信号呢?

SIGHUP会在以下3种情况下被发送给相应的进程:

1、终端关闭时,该信号被发送到session首进程以及作为job提交的进程(即用 & 符号提交的进程)

2、session首进程退出时,该信号被发送到该session中的前台进程组中的每一个进程

3、若父进程退出导致进程组成为孤儿进程组,且该进程组中有进程处于停止状态(收到SIGSTOP或SIGTSTP信号),该信号会被发送到该进程组中的每一个进程。

结合 1和2 我们知道,不管是否以 & (job方式)启动的进程,关闭终端时都会收到  SIGHUP 信号 ,那么进程收到 SIGHUP 信号会如何处理呢?

系统对SIGHUP信号的默认处理是终止收到该信号的进程。所以若程序中没有捕捉该信号,当收到该信号时,进程就会退出。

也就是说关闭终端进程会收到SIGHUP信号,而该信号的默认处理方式就是结束掉该进程,当然我们也可以自己捕获处理该信号,或者忽略它

我们在命令行运行该例程,然后直接关闭掉该shell终端窗口,然后重新打开一个终端查看这个进程是否还在运行:

[root@localhost php]# ps -ef | grepdeadloop.php

root    16112     1  0 17:20 ?        00:00:00 php deadloop.php

root    16138 16115  0 17:24 pts/4    00:00:00 grep deadloop.php

[root@localhost php]# cat logs.txt

pid : 16112 receive SIGHUP 信号

 

可以看到deadloop.php 仍在运行,而其父进程变成了init 进程 (由于其原本父进程退出了从而被init进程收养),从写到的文件内容也可以看到 关闭终端进程收到了SIGHUP 信号。其实我们不必这么麻烦,只需要使用linux提供给我们的nohup命令,但我们使用nohup启动进程时,进程会忽略收到的SIGHUP信号,也就不会退出了,首先去掉刚才的信号处理代码。然后nohup运行。

并且nohup默认会把程序的输出重定向到当前目录下的nohup.out文件,如果没有可写权限,则写入$homepath/nohup.out

所以当我们组合nohup 和 & 两种方式时,启动的进程不会占用控制台,也不依赖控制台,控制台关闭之后进程被1号进程收养,成为孤儿进程,这就和守护进程的机制非常类似了。

nohup php deadloop.php >logs.txt2>error.txt &

其中>logs.txt 重定向标准输出,2>error.txt重定向标准错误输出。

第二种实现方式(未验证)

就是根据守护进程的规则和特点通过代码来实现,守护进程最大的特点就是脱离了用户终端和会话。

想要使用这种方式需要安装

yum install php70w-process

$pid = pcntl_fork();

if ($pid == -1)

{

   throw new Exception('fork子进程失败');

}

elseif ($pid > 0)

{

   //父进程退出,子进程不是进程组长,以便接下来顺利创建新会话

   exit(0);

}

// 最重要的一步,创建一个新的会话,脱离原来的控制终端

posix_setsid();

// 修改当前进程的工作目录,由于子进程会继承父进程的工作目录,修改工作目录以释放对父进程工作目录的占用。

chdir('/');

/*

 *通过上一步,我们创建了一个新的会话组长,进程组长,且脱离了终端,但是会话组长可以申请重新打开一个终端,为了避免

 *这种情况,我们再次创建一个子进程,并退出当前进程,这样运行的进程就不再是会话组长。

 */

$pid = pcntl_fork();

if ($pid == -1)

{

   throw new Exception('fork子进程失败');

}

elseif ($pid > 0)

{

   //  再一次退出父进程,子进程成为最终的守护进程

   exit(0);

}

// 由于守护进程用不到标准输入输出,关闭标准输入,输出,错误输出描述符

fclose(STDIN);

fclose(STDOUT);

fclose(STDERR);

/*

 *处理业务代码

 */

while(TRUE)

{

   file_put_contents('log.txt', time().PHP_EOL, FILE_APPEND);

   sleep(5);

}

开机自启动

创建sh脚本

赋权脚本可执行的权限

Chmod +x /usr/share/nginx/html/swoole.php

添加开机自启动脚本(验证OK)

打开/etc/rc.d/rc.local文件,在末尾添加如下内容

echo "/home/yingshan.sh" >>/etc/rc.d/rc.local  

在centos7中,/etc/rc.d/rc.local的权限被降低了,所以需要执行如下命令赋予其可执行的权限

Chmod + x /etc/rc.d/rd.local

方法二(验证OK)

在/etc/rc.d/init.d 下创建test.sh 脚本

#!/bin/bash

# description: 测试开机自启动的php脚本

/usr/share/nginx/html/test.php

增加脚本的可执行权限

将脚本添加到开机自启动项目中去

chkconfig test.sh on

检查sh脚本

直接运行报如下错误

这里啊 需要添加的是执行的脚本命令 而非脚本本身

不支持chkconfig

#!/bin/sh

#chkconfig: 2345 80 90

#description:auto_run

第一行,告诉系统使用的shell,所有的shell脚本都是这样。

第二行,chkconfig后面有三个参数2345,80和90

告诉chkconfig程序,需要在rc2.d~rc5.d目录下,创建名字为 S80auto_run的文件连接,连接到/etc/rc.d/init.d目录下的的auto_run脚本。

第一个字符是S,系统在启动的时候,运行脚 本auto_run,就会添加一个start参数,告诉脚本,现在是启动模式。同时在rc0.d和rc6.d目录下,创建名字为K90auto_run的文件连接,第一个字符为K,个系统在关闭系统的时候,会运行auto_run,添加一个stop,告诉脚本,现在是关闭模式。

注意上面的三行是中,地二,第三行是必须的,否则在运行chkconfig --add

auto_run时,会报错。

Vagrant box 下的文件共享错误

当使用共享文件(夹)时,系统开机时,优先检测开机项,执行到sh脚本后,如果该脚本指定的文件在共享文件夹下面,则会提示无法打开该文件,实际上是因为文件共享系统尚未同步,因此找不到该文件,避免这种情况,可以将脚本放在服务器上。

另外说明下,使用vagrant shutdown后所有的内在配置会丢失,而reboot则不会。

推荐阅读更多精彩内容