欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

PHP實現(xiàn)守護(hù)進(jìn)程的示例代碼

 更新時間:2022年05月11日 15:34:18   作者:Yian  
守護(hù)進(jìn)程到底是怎么實現(xiàn)的?為什么有的程序既可以自己就成為守護(hù)進(jìn)程,又可以通過systemd 來后臺運(yùn)行?本文將為大家具體講解,感興趣的可以了解一下

前言

寫 PHP CLI 程序的老司機(jī)們可能經(jīng)常會寫一些常駐進(jìn)程,比如消息隊列消費(fèi)者進(jìn)程,這些進(jìn)程會一直運(yùn)行,除非要發(fā)版,不然一般不會重啟的,所以程序程序是不可能由我們通過 ssh 登錄到服務(wù)器上通過終端來直接啟動的(因為一旦斷開 ssh 進(jìn)程就退出了),常見的做法就是用 systemd 或者 supervisor 來使其成為 守護(hù)進(jìn)程,這樣進(jìn)程就可以一直運(yùn)行,遇到錯誤意外退出也能被自動重啟。

好學(xué)的你可能會思考守護(hù)進(jìn)程到底是怎么實現(xiàn)的?為什么有的程序既可以自己就成為守護(hù)進(jìn)程,又可以通過 systemd 來后臺運(yùn)行?如果不依賴外部,我們的 PHP 程序該怎樣變成守護(hù)進(jìn)程呢?

成為守護(hù)進(jìn)程的步驟

其實只需要創(chuàng)建子進(jìn)程并退出父進(jìn)程,將要處理的工作在子進(jìn)程中進(jìn)行就可以實現(xiàn)一個守護(hù)進(jìn)程了。但是僅僅是這么做的話,如果后續(xù)任務(wù)很復(fù)雜,或者引入了一些第三方包,那么可能就會出現(xiàn)奇奇怪怪的問題了。

而在《UNIX環(huán)境高級編程》(英語:Advanced Programming in the UNIX Environment,簡稱APUE)一書中有介紹關(guān)于守護(hù)進(jìn)程的編碼規(guī)范,我們按照規(guī)范來實現(xiàn)我們的守護(hù)進(jìn)程就可以避免出現(xiàn)那些奇怪的問題了。而且規(guī)范也不復(fù)雜,只需要幾步就可以了:

  • 創(chuàng)建子進(jìn)程,退出父進(jìn)程
  • 子進(jìn)程創(chuàng)建一個新的會話并成為 session leader
  • 重設(shè)文件掩碼
  • 改變工作目錄
  • 關(guān)閉標(biāo)準(zhǔn)輸入輸出

實現(xiàn)

<?php

function daemon()
{
    // [1] 創(chuàng)建子進(jìn)程
    $pid = pcntl_fork();
    if ($pid == -1) {
        die('fork failed');
    }

    // [2] 如果是父進(jìn)程,則退出
    if ($pid > 0) {
        exit(0);
    }

    ///////////////// 以下是子進(jìn)程 /////////////////

    // [3] 創(chuàng)建一個新的會話并成為 session leader
    if ( ($sid = posix_setsid()) <= 0 ) {
        die("Set sid failed.\n");
    }

    // [4] 重設(shè)文件掩碼
    umask(0);

    // [5] 改變工作目錄
    if (chdir('/') === false) {
        die("chdir failed.\n");
    }

    // [6] 關(guān)閉標(biāo)準(zhǔn)輸入輸出
    fclose(STDIN);
    fclose(STDOUT);
    fclose(STDERR);
}

daemon();

// ... 真正的處理邏輯

說明

上面短短的十幾二十行代碼就實現(xiàn)了一個守護(hù)進(jìn)程,接下來解釋一下有些步驟為什么要這么做。

創(chuàng)建子進(jìn)程并退出父進(jìn)程

pcntl_fork() 的返回值有三種情況,上面的代碼([1]和[2])已經(jīng)處理了對應(yīng)的情況。

創(chuàng)建新的會話

調(diào)用 posix_setsid() 創(chuàng)建新會話會使得當(dāng)前進(jìn)程成為新會話中的“會話首進(jìn)程”,同時也會使當(dāng)前進(jìn)程成為“進(jìn)程組組長”,并且使得當(dāng)前進(jìn)程脫離控制終端。

重設(shè)文件掩碼

調(diào)用 umask() 重設(shè)文件掩碼,這里通常是 0。為什么是 0 而不是其他呢,因為子進(jìn)程從父進(jìn)程繼承來的文件掩碼可能會屏蔽某些特定的文件操作權(quán)限。比如說引入的第三方庫可能需要用特定的權(quán)限來創(chuàng)建文件,并且它沒有將文件權(quán)限作為一個選項參數(shù)由你指定,那么就可能會出現(xiàn)失敗的情況;而我們傳入 0,會使得從調(diào)用了 umask() 之后,守護(hù)進(jìn)程創(chuàng)建的文件權(quán)限為 0666,目錄權(quán)限為 0777,均為最高權(quán)限。

關(guān)于 umask() 后面會展開新的篇幅來說明,感興趣的可以先自行搜索資料學(xué)習(xí)。

改變工作目錄

通過 chdir() 我們將工作目錄設(shè)置為根目錄 /,主要是因為守護(hù)進(jìn)程是長時間運(yùn)行的,通常只有系統(tǒng)關(guān)閉/重啟才會退出。假如從父進(jìn)程繼承來的工作目錄是個掛載的文件系統(tǒng),如果不改變工作目錄,那么將會導(dǎo)致這個掛載的文件系統(tǒng)一直沒法卸載。

當(dāng)然也不一定要將工作目錄切換到根目錄,你也可以根據(jù)實際情況切換到特定的目錄。

關(guān)閉標(biāo)準(zhǔn)輸入輸出

因為守護(hù)進(jìn)程是脫離終端控制的,所以是沒有標(biāo)準(zhǔn)輸入輸出交互的,我們將其關(guān)閉即可。

其他

二次 fork

你可能在一些資料中看到有人推薦你在 [3] 創(chuàng)建一個新的會話并成為 session leader 之后再次進(jìn)行 fork。這一步驟是在基于 System V 的系統(tǒng)中,可以保證你的守護(hù)進(jìn)程不是“會話首進(jìn)程”,可以阻止其重新申請獲取一個控制終端。

關(guān)閉不必要的文件描述符

按照編碼規(guī)范,實際還有一步是關(guān)閉不必要的文件描述符。但我們?yōu)榱撕唵纹鹨?,上面的代碼在進(jìn)程啟動之后先創(chuàng)建守護(hù)進(jìn)程再執(zhí)行其他操作,因此這里只打開了三個文件描述符: 0、1 和 2(即標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)錯誤)。

注意事項

因為上面的代碼將標(biāo)準(zhǔn)輸入輸出關(guān)閉了,也就是說如果你在 daemon() 之后有諸如 echo "Hello world"; 之類的輸出,那么你的程序?qū)鲥e然后退出,并且你將看不到任何錯誤信息(因為標(biāo)準(zhǔn)錯誤也被關(guān)閉了)。

解決方案有兩種,一種是用 file_put_contents 代替 echo,但是這樣并不優(yōu)雅,而且萬一引入的第三方包中寫了 echo 或者是 file_put_contents(STDOUT, ...),那你的程序也會“莫名其妙”就掛了,會讓你排查半天到底是哪里出了問題。

因此我們還可以在第[6]之后加入:

// [7] 重定向輸入輸出
    global $stdin, $stdout, $stderr;
    $stdin = fopen('/dev/null', 'r');
    $stdout = fopen('/dev/null', 'wb'); // 你也可以將標(biāo)準(zhǔn)輸出重定向到指定的文件,相當(dāng)于是日志
    $stderr = fopen('/dev/null', 'wb'); // 同上

到此這篇關(guān)于PHP實現(xiàn)守護(hù)進(jìn)程的示例代碼的文章就介紹到這了,更多相關(guān)PHP守護(hù)進(jìn)程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • php魔術(shù)變量用法實例詳解

    php魔術(shù)變量用法實例詳解

    這篇文章主要介紹了php魔術(shù)變量用法,以實例形式詳細(xì)分析了php中常見的各種魔術(shù)變量的具體用法,并補(bǔ)充說明了php中的魔術(shù)方法,具有不錯的參考借鑒價值,需要的朋友可以參考下
    2014-11-11
  • PHP從尾到頭打印鏈表實例講解

    PHP從尾到頭打印鏈表實例講解

    這篇文章給大家分享了關(guān)于PHP從尾到頭打印鏈表的相關(guān)知識點內(nèi)容,有需要的朋友們可以測試下。
    2018-09-09
  • PHP syntax error, unexpected $end 錯誤的一種原因及解決

    PHP syntax error, unexpected $end 錯誤的一種原因及解決

    PHP 遇到 syntax error, unexpected $end 錯誤時,查錯思路其實還是看看文件里 PHP 的開始標(biāo)記和結(jié)束標(biāo)記是否配對,還要額外注意注釋里是否出現(xiàn)過 ?> 喲。
    2008-10-10
  • PHP多線程類及用法實例

    PHP多線程類及用法實例

    這篇文章主要介紹了PHP多線程類及用法,實例分析了多線程類的具體實現(xiàn)方法及應(yīng)用技巧,并結(jié)合下載遠(yuǎn)程圖片的實例予以深入分析,需要的朋友可以參考下
    2014-12-12
  • PHP的array_diff()函數(shù)在處理大數(shù)組時的效率問題

    PHP的array_diff()函數(shù)在處理大數(shù)組時的效率問題

    PHP 5.2.6 以上版本的 array_diff() 函數(shù)在處理大數(shù)組時,需要花費(fèi)超長時間,這個 bug 已經(jīng)被官方確認(rèn);在這個問題被修復(fù)之前或者在我們不能控制 PHP 版本的時候,可以使用本文提供的方法
    2011-11-11
  • PHP中功能強(qiáng)大卻很少使用的函數(shù)實例小結(jié)

    PHP中功能強(qiáng)大卻很少使用的函數(shù)實例小結(jié)

    這篇文章主要介紹了PHP中功能強(qiáng)大卻很少使用的函數(shù),結(jié)合實例形式總結(jié)分析了php中非常實用的幾個函數(shù),包括函數(shù)的調(diào)用、注冊、調(diào)用、判斷等操作技巧,需要的朋友可以參考下
    2016-11-11
  • php foreach循環(huán)中使用引用的問題

    php foreach循環(huán)中使用引用的問題

    本文來給大家介紹php foreach循環(huán)中使用引用問題分析與注意事項,希望此文章對各位同學(xué)會有所幫助
    2013-11-11
  • PHP 獲取遠(yuǎn)程文件內(nèi)容的函數(shù)代碼

    PHP 獲取遠(yuǎn)程文件內(nèi)容的函數(shù)代碼

    PHP 獲取遠(yuǎn)程文件內(nèi)容的代碼,后面有一些注釋可以參考下,其實大家可以參考腳本之家發(fā)布的一些采集程序代碼。
    2010-03-03
  • PHP與SQL注入攻擊[一]

    PHP與SQL注入攻擊[一]

    PHP與SQL注入攻擊[一]...
    2007-04-04
  • header與緩沖區(qū)之間的深層次分析

    header與緩沖區(qū)之間的深層次分析

    實際的開發(fā)中,大家是否聽說過在header之前不能有任何的實際輸出。甚至有的認(rèn)為header函數(shù)必須寫在代碼的最前面??墒悄闶欠裨囼炦^header函數(shù)之前輸出東西?下來讓我們更深層次的了解一下
    2016-07-07

最新評論