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则不会。
网友评论