PHP 實現守護進

JaguarJack發表於2019-08-08

原文轉載於 PHP 實現守護進

守護程式

守護程式作為一種常駐程式服務,很常見,例如 PHP-FPM, NGINX,REDIS,都需要一個父程式來支援整個服務。但是用 PHP 編寫守護程式不多見,今天就來用 PHP 來實現一下。

步驟

  • fork 子程式
  • 父程式退出
  • 設定新的會話
  • 重置檔案掩碼
  • 關閉標準輸入輸出

實現

我們對著以上的步驟來實現,在這之前需要 pcntlposix 擴充套件,請確保安裝了。

function daemon() {

    $pid = pcntl_fork();
    // fork 失敗
    if ($pid < 0) {
        exit('fork failed');
    } else if ($pid > 0) {
       // 退出父程式
        exit(0);
    }

    // 設定新的會員
    // setsid 有幾個注意點
    // 不能是程式組的組長呼叫
    // 對於程式組組員呼叫會產生新的會話和程式組,併成為該程式組的唯一成員,呼叫的程式將脫離終端
    if (posix_setsid() < 0) {
        exit('set sid failed');
    }
    // 重置檔案掩碼
    umask(0);
    // 切換工作目錄
    chdir('/');
    // 關閉標準輸入輸出
    fclose(STDIN);
    fclose(STDOUT);
    fclose(STDERR);

}

細節

// 獲取程式ID
var_dump(posix_getpid());
// 獲取程式組ID
var_dump(posix_getpgid(posix_getpid()));
// 獲取程式會話ID    
var_dump(posix_getsid(posix_getpid()));

三者結果相同,說明了該程式即使程式組的組長,也是會話首領。

為什麼需要 umask(0)

當你在 linux 呼叫 umask 的時候你會看到一個掩碼值,這個掩碼決定了你建立檔案許可權範圍,例如本人當前機器的 umask 為

0022

檔案的最大許可權是 0666,而目錄的最大許可權是 0777, 那麼當前使用者的建立的目錄許可權就是 0755,對於當前使用者而言就是 rwx-rx-rx 許可權。而檔案則是 0644,對於當前使用者而言 rw-r-r 許可權。所以如果沒有重置掩碼的話,那麼對於目錄而言就是 0755,而檔案則是 0644了。

注意

如果你在程式使用了 echo var_dump 等函式,一定要把標準輸出等重定向到其他檔案流中。新增加下面程式碼就可以了。

global $stdin, $stdout, $stderr;
$stdin = fopen('/dev/null', 'r');
$stdout = fopen('/www/php/txt.txt','wb');
$stderr = fopen('/dev/null', 'wb');

因為在上面已經關閉了標準輸入輸出,此時檔案描述符 fd 已經沒有,所有重新開啟之後 fd 從非負開始依次是 0,1,2。正好作為標準輸入輸出的檔案。當然重定向到那裡需要你自己設定。

最後的二次 fork

這個問題需要好好斟酌,因為是非必須的。目前想不到有什麼場景下必須兩次 Fork。

相關文章