PHP守護(hù)進(jìn)程的方式
借助nohup 和& 配合使用(驗(yàn)證OK)
在命令后面加上&符合,可以讓啟動(dòng)的進(jìn)程轉(zhuǎn)到后臺(tái)運(yùn)行,而不占用控制臺(tái),控制臺(tái)還可以再運(yùn)行其它的命令。示例如下:
?While(true){
?echotime().PHP_EOL;
?sleep(3);
}
用&方式來啟動(dòng)該進(jìn)程
Php deadloop.php &
查看該進(jìn)程狀態(tài)
Ps aux | grep
這時(shí)我們可以通過fg命令讓進(jìn)程恢復(fù)到普通占用控制臺(tái)的模式
Fg
在命令之前加上nohup ,啟動(dòng)的進(jìn)程將會(huì)忽略linux的掛起信號(hào) (SIGHUP),
那什么情況下會(huì)觸發(fā)linux下SIGHUP信號(hào)呢?
SIGHUP會(huì)在以下3種情況下被發(fā)送給相應(yīng)的進(jìn)程:
1、終端關(guān)閉時(shí),該信號(hào)被發(fā)送到session首進(jìn)程以及作為job提交的進(jìn)程(即用 & 符號(hào)提交的進(jìn)程)
2、session首進(jìn)程退出時(shí),該信號(hào)被發(fā)送到該session中的前臺(tái)進(jìn)程組中的每一個(gè)進(jìn)程
3、若父進(jìn)程退出導(dǎo)致進(jìn)程組成為孤兒進(jìn)程組,且該進(jìn)程組中有進(jìn)程處于停止?fàn)顟B(tài)(收到SIGSTOP或SIGTSTP信號(hào)),該信號(hào)會(huì)被發(fā)送到該進(jìn)程組中的每一個(gè)進(jìn)程。
結(jié)合 1和2 我們知道,不管是否以 & (job方式)啟動(dòng)的進(jìn)程,關(guān)閉終端時(shí)都會(huì)收到 ?SIGHUP 信號(hào) ,那么進(jìn)程收到 SIGHUP 信號(hào)會(huì)如何處理呢?
系統(tǒng)對(duì)SIGHUP信號(hào)的默認(rèn)處理是終止收到該信號(hào)的進(jìn)程。所以若程序中沒有捕捉該信號(hào),當(dāng)收到該信號(hào)時(shí),進(jìn)程就會(huì)退出。
也就是說關(guān)閉終端進(jìn)程會(huì)收到SIGHUP信號(hào),而該信號(hào)的默認(rèn)處理方式就是結(jié)束掉該進(jìn)程,當(dāng)然我們也可以自己捕獲處理該信號(hào),或者忽略它

我們?cè)诿钚羞\(yùn)行該例程,然后直接關(guān)閉掉該shell終端窗口,然后重新打開一個(gè)終端查看這個(gè)進(jìn)程是否還在運(yùn)行:
[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 信號(hào)
?
可以看到deadloop.php 仍在運(yùn)行,而其父進(jìn)程變成了init 進(jìn)程 (由于其原本父進(jìn)程退出了從而被init進(jìn)程收養(yǎng)),從寫到的文件內(nèi)容也可以看到 關(guān)閉終端進(jìn)程收到了SIGHUP 信號(hào)。其實(shí)我們不必這么麻煩,只需要使用linux提供給我們的nohup命令,但我們使用nohup啟動(dòng)進(jìn)程時(shí),進(jìn)程會(huì)忽略收到的SIGHUP信號(hào),也就不會(huì)退出了,首先去掉剛才的信號(hào)處理代碼。然后nohup運(yùn)行。

并且nohup默認(rèn)會(huì)把程序的輸出重定向到當(dāng)前目錄下的nohup.out文件,如果沒有可寫權(quán)限,則寫入$homepath/nohup.out

所以當(dāng)我們組合nohup 和 & 兩種方式時(shí),啟動(dòng)的進(jìn)程不會(huì)占用控制臺(tái),也不依賴控制臺(tái),控制臺(tái)關(guān)閉之后進(jìn)程被1號(hào)進(jìn)程收養(yǎng),成為孤兒進(jìn)程,這就和守護(hù)進(jìn)程的機(jī)制非常類似了。

nohup php deadloop.php >logs.txt2>error.txt &
其中>logs.txt 重定向標(biāo)準(zhǔn)輸出,2>error.txt重定向標(biāo)準(zhǔn)錯(cuò)誤輸出。
第二種實(shí)現(xiàn)方式(未驗(yàn)證)
就是根據(jù)守護(hù)進(jìn)程的規(guī)則和特點(diǎn)通過代碼來實(shí)現(xiàn),守護(hù)進(jìn)程最大的特點(diǎn)就是脫離了用戶終端和會(huì)話。
想要使用這種方式需要安裝
yum?install?php70w-process
$pid = pcntl_fork();
if ($pid == -1)
{
???throw new Exception('fork子進(jìn)程失敗');
}
elseif ($pid > 0)
{
???//父進(jìn)程退出,子進(jìn)程不是進(jìn)程組長(zhǎng),以便接下來順利創(chuàng)建新會(huì)話
???exit(0);
}
// 最重要的一步,創(chuàng)建一個(gè)新的會(huì)話,脫離原來的控制終端
posix_setsid();
// 修改當(dāng)前進(jìn)程的工作目錄,由于子進(jìn)程會(huì)繼承父進(jìn)程的工作目錄,修改工作目錄以釋放對(duì)父進(jìn)程工作目錄的占用。
chdir('/');
/*
?*通過上一步,我們創(chuàng)建了一個(gè)新的會(huì)話組長(zhǎng),進(jìn)程組長(zhǎng),且脫離了終端,但是會(huì)話組長(zhǎng)可以申請(qǐng)重新打開一個(gè)終端,為了避免
?*這種情況,我們?cè)俅蝿?chuàng)建一個(gè)子進(jìn)程,并退出當(dāng)前進(jìn)程,這樣運(yùn)行的進(jìn)程就不再是會(huì)話組長(zhǎng)。
?*/
$pid = pcntl_fork();
if ($pid == -1)
{
???throw new Exception('fork子進(jìn)程失敗');
}
elseif ($pid > 0)
{
???//? 再一次退出父進(jìn)程,子進(jìn)程成為最終的守護(hù)進(jìn)程
???exit(0);
}
// 由于守護(hù)進(jìn)程用不到標(biāo)準(zhǔn)輸入輸出,關(guān)閉標(biāo)準(zhǔn)輸入,輸出,錯(cuò)誤輸出描述符
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
/*
?*處理業(yè)務(wù)代碼
?*/
while(TRUE)
{
???file_put_contents('log.txt', time().PHP_EOL, FILE_APPEND);
???sleep(5);
}
開機(jī)自啟動(dòng)
創(chuàng)建sh腳本

賦權(quán)腳本可執(zhí)行的權(quán)限
Chmod +x /usr/share/nginx/html/swoole.php
添加開機(jī)自啟動(dòng)腳本(驗(yàn)證OK)
打開/etc/rc.d/rc.local文件,在末尾添加如下內(nèi)容
echo "/home/yingshan.sh" >>/etc/rc.d/rc.local??
在centos7中,/etc/rc.d/rc.local的權(quán)限被降低了,所以需要執(zhí)行如下命令賦予其可執(zhí)行的權(quán)限
Chmod + x /etc/rc.d/rd.local

方法二(驗(yàn)證OK)
在/etc/rc.d/init.d 下創(chuàng)建test.sh 腳本
#!/bin/bash
# description: 測(cè)試開機(jī)自啟動(dòng)的php腳本
/usr/share/nginx/html/test.php
增加腳本的可執(zhí)行權(quán)限

將腳本添加到開機(jī)自啟動(dòng)項(xiàng)目中去

chkconfig test.sh on
檢查sh腳本
直接運(yùn)行報(bào)如下錯(cuò)誤

這里啊 需要添加的是執(zhí)行的腳本命令?而非腳本本身
不支持chkconfig
#!/bin/sh
#chkconfig: 2345 80 90
#description:auto_run
第一行,告訴系統(tǒng)使用的shell,所有的shell腳本都是這樣。
第二行,chkconfig后面有三個(gè)參數(shù)2345,80和90
告訴chkconfig程序,需要在rc2.d~rc5.d目錄下,創(chuàng)建名字為 S80auto_run的文件連接,連接到/etc/rc.d/init.d目錄下的的auto_run腳本。
第一個(gè)字符是S,系統(tǒng)在啟動(dòng)的時(shí)候,運(yùn)行腳 本auto_run,就會(huì)添加一個(gè)start參數(shù),告訴腳本,現(xiàn)在是啟動(dòng)模式。同時(shí)在rc0.d和rc6.d目錄下,創(chuàng)建名字為K90auto_run的文件連接,第一個(gè)字符為K,個(gè)系統(tǒng)在關(guān)閉系統(tǒng)的時(shí)候,會(huì)運(yùn)行auto_run,添加一個(gè)stop,告訴腳本,現(xiàn)在是關(guān)閉模式。
注意上面的三行是中,地二,第三行是必須的,否則在運(yùn)行chkconfig --add
auto_run時(shí),會(huì)報(bào)錯(cuò)。
Vagrant box 下的文件共享錯(cuò)誤
當(dāng)使用共享文件(夾)時(shí),系統(tǒng)開機(jī)時(shí),優(yōu)先檢測(cè)開機(jī)項(xiàng),執(zhí)行到sh腳本后,如果該腳本指定的文件在共享文件夾下面,則會(huì)提示無法打開該文件,實(shí)際上是因?yàn)槲募蚕硐到y(tǒng)尚未同步,因此找不到該文件,避免這種情況,可以將腳本放在服務(wù)器上。

另外說明下,使用vagrant shutdown后所有的內(nèi)在配置會(huì)丟失,而reboot則不會(huì)。
