首頁 > 後端開發 > php教程 > php中兩種守護程式的方式

php中兩種守護程式的方式

墨辰丷
發布: 2023-03-25 19:22:01
原創
1695 人瀏覽過

這篇文章主要介紹php中兩種守護程式的方式,有興趣的夥伴參考下,希望可以幫助到大家。

第一種方式,借助 nohup 和 &  配合使用。

在命令後面加上& 符號, 可以讓啟動的進程轉到後台運行,而不佔用控制台,控制台還可以再運行其他命令,這裡我使用一個while死循環來做演示,程式碼如下

<?php

while(true){
        echo time().PHP_EOL;
        sleep(3);
}
登入後複製


用& 方式來啟動該進程

[root@localhost php]# php deadloop.php &
[1] 3454
[root@localhost php]# ps aux | grep 3454
root      
3454  0.0  0.8 284544  8452 pts/0    
T    18:06   0:00 php deadloop.php
root      
3456  0.0  0.0 103316   896 pts/0    
S+   18:08   0:00 grep 3454

[1]+  Stopped                 
php deadloop.php
[root@localhost php]#
登入後複製


可以看到該進程並未佔用控制台,控制台還可以運行其他命令,這時我們也可以透過fg 指令讓進程恢復到普通佔用控制台的模式。



[root@localhost php]# fg
php deadloop.php
1470996682
1470996685
1470996688
1470996691
登入後複製


以上就是關於& 指令簡單介紹


##下面再來看另一個指令nohup

在指令之前加上nohup ,啟動的進程將會忽略linux的掛起訊號(SIGHUP),那什麼情況下會觸發linux下SIGHUP訊號呢,下列內容摘自百度百科:


SIGHUP会在以下3种情况下被发送给相应的进程:
1、终端关闭时,该信号被发送到session首进程以及作为job提交的进程(即用 & 符号提交的进
程)
2、session首进程退出时,该信号被发送到该session中的前台进程组中的每一个进程
3、若父进程退出导致进程组成为孤儿进程组,且该进程组中有进程处于停止状态(收到SIGSTOP或
SIGTSTP信号),该信号会被发送到该进程组中的每一个进程。
登入後複製

結合1和2 我們知道,不管是否以& (job方式)啟動的進程,關閉終端機時都會收到 SIGHUP 訊號,那麼進程收到SIGHUP 訊號會如何處理呢,看同樣是摘自百度百科的一句話

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

#也就是說關閉終端進程會收到SIGHUP訊號,而該訊號的預設處理方式就是結束掉該進程,當然我們也可以自己捕獲處理該信號,或者忽略它,例如以下代碼

<?php
pcntl_signal(SIGHUP, function(){
   //这地方处理信号的方式我们只是简单的写入一句日志到文件中
   file_put_contents(&#39;logs.txt&#39;, &#39;pid : &#39; . posix_getpid() . &#39; 
   receive SIGHUP 信号&#39; . PHP_EOL);
});
        
while(1) {
        sleep(10);
        pcntl_signal_dispatch();
}
登入後複製

我們在命令行運行該例程,然後直接關閉掉該shell終端窗口,然後重新打開一個終端查看這個進程是否還在運行:

[root@localhost php]# ps -ef | grep deadloop.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 運行。


[root@localhost php]# nohup php deadloop.php 
nohup: 忽略输入并把输出追加到"nohup.out"
登入後複製


並且nohup預設會把程式的輸出重新導向到目前目錄下的nohup.out文件,如果沒有可寫權限,則寫入$homepath/nohup.out


[root@localhost php]# ls
cmd.sh  deadloop.php  getPhoto.php  nohup.out  pics
[root@localhost php]# tail -f nohup.out 
1470999772
1470999775
1470999778
1470999781
1470999784
1470999787
1470999790
1470999793
1470999796
1470999799
1470999802
登入後複製

此時關閉終端,進程不會結束,而是變成了孤​​兒進程(ppid=1 ),因為創建它的父進程退出了。




[root@localhost ~]# ps -ef | grep 3554
root      3554  3497  0 19:09 pts/0    00:00:00 php deadloop.php
root      3575  3557  0 19:10 pts/1    00:00:00 grep 3554
[root@localhost ~]# ps -ef | grep 3554
root      3554     1  0 19:09 ?     00:00:00 php deadloop.php
root      3577  3557  0 19:10 pts/1    00:00:00 grep 3554
[root@localhost ~]#
登入後複製



結論: 所以當我們組合nohup 和& 兩種方式時,啟動的進程不會佔用控制台,也不依賴控制台,控制台關閉之後進程被1號進程收養,成為孤兒進程,這就和守護進程的機制非常類似了。


[root@localhost php]# nohup php deadloop.php >logs.txt 2>error.txt &
[1] 3612
[root@localhost php]# ps -ef |grep 3612
root      3612  3557  0 19:18 pts/1    00:00:00 php deadloop.php
root      3617  3557  0 19:19 pts/1    00:00:00 grep 3612
[root@localhost php]#
登入後複製

其中 >logs.txt 重定向標準輸出,2>error.txt 重定向標準錯誤輸出。


以上就是關於第一種實作方式的介紹。

第二種實現方式就是根據守護程式的規則和特點透過程式碼來實現,守護程式最大的特點就是脫離了使用者終端和會話,以下是實現的程式碼,關鍵地方進行了註解。

<?php
$pid = pcntl_fork();
if ($pid == -1)
{
    throw new Exception(&#39;fork子进程失败&#39;);
}
elseif ($pid > 0)
{
    //父进程退出,子进程不是进程组长,以便接下来顺利创建新会话
    exit(0);
}

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

// 修改当前进程的工作目录,由于子进程会继承父进程的工作目录,修改工作目录以释放对父进
程工作目录的占用。
chdir(&#39;/&#39;);

/*
 * 通过上一步,我们创建了一个新的会话组长,进程组长,且脱离了终端,但是会话组长可以
 申请重新打开一个终端,为了避免
 * 这种情况,我们再次创建一个子进程,并退出当前进程,这样运行的进程就不再是会话组长。
 */
$pid = pcntl_fork();
if ($pid == -1)
{
    throw new Exception(&#39;fork子进程失败&#39;);
}
elseif ($pid > 0)
{
    //  再一次退出父进程,子进程成为最终的守护进程
    exit(0);
}

// 由于守护进程用不到标准输入输出,关闭标准输入,输出,错误输出描述符
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);

/*
 * 处理业务代码
 */

while(TRUE)
{
    file_put_contents(&#39;log.txt&#39;, time().PHP_EOL, FILE_APPEND);
    sleep(5);
}
登入後複製


相關推薦:


PHP進程訊號處理

##PHP進程間通訊詳解


PHP進程鎖定如何實作

以上是php中兩種守護程式的方式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板