首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 編寫守護進程實戰:基於 pcntl + sockets 實現 HTTP 服務器

     編輯:PHP 綜合知識

PHP CLI SAPI 與守護進程

PHP 從 4.3 版本引入 CLI SAPI,配合 pcntl (進程控制) 和 posix (POSIX 函數) 擴展,可編寫長運行的守護進程、信號處理、多進程並發程序。

雙重 Fork 守護進程模式

function run() {
    // 第一次 fork:父進程退出,子進程成為孤兒進程,由 init 收養
    if (($pid1 = pcntl_fork()) === 0) {
        // 子進程:創建新會話,脫離終端控制
        posix_setsid();
        
        // 第二次 fork:防止會話首進程重新獲得控制終端
        if (($pid2 = pcntl_fork()) === 0) {
            // 真正的守護進程:執行業務邏輯
            handle_http_request('0.0.0.0', 9999);
        } else {
            // 第一子進程退出
            exit(0);
        }
    } else {
        // 父進程等待第一子進程退出
        pcntl_wait($status);
    }
}

Socket HTTP 服務器核心邏輯

function handle_http_request($address, $port) {
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    socket_bind($socket, $address, $port);
    socket_listen($socket, 16); // backlog
    
    $response = "HTTP/1.1 200 OK\r\n" .
                "Content-Length: 15\r\n" .
                "Content-Type: text/plain; charset=UTF-8\r\n\r\n" .
                "PHP HTTP Server";
    $resLen = strlen($response);
    
    while (true) {
        $client = socket_accept($socket);
        if ($client !== false) {
            socket_write($client, $response, $resLen);
            socket_close($client);
        }
    }
}

關鍵技術點解析

1. pcntl_fork() 進程分叉

  • 父進程返回子進程 PID
  • 子進程返回 0
  • 失敗返回 -1

2. posix_setsid() 會話領導者

  • 創建新會話,進程成為會話首進程
  • 脫離控制終端,避免終端關閉發送 SIGHUP
  • 進程組長 = 會話首進程 = 進程 PID

3. 雙重 Fork 意義

4. Socket 非阻塞與多路複用 (生產級擴展)

// 設置非阻塞
socket_set_nonblock($socket);

// 使用 select/poll/epoll 監聽多個 fd
$read = [$socket];
$write = $except = null;
while (socket_select($read, $write, $except, 1) > 0) {
    if (in_array($socket, $read)) {
        $client = socket_accept($socket);
        // 加入客戶端 fd 到 $read 陣列...
    }
    // 處理可讀/可寫客戶端...
}

信號處理優雅關閉

$shutdown = false;
pcntl_signal(SIGTERM, function() use (&$shutdown) { $shutdown = true; });
pcntl_signal(SIGINT, function() use (&$shutdown) { $shutdown = true; });

while (!$shutdown) {
    // 主循環
    pcntl_signal_dispatch(); // 處理信號
    // ...
}
// 清理資源、關閉 socket、保存狀態
exit(0);

進程管理最佳實踐

  1. PID 文件:啟動時寫入 /var/run/mydaemon.pid,停止讀取 kill
  2. 日誌輪轉:輸出到 stdout/stderr,由 systemd/supervisord 管理
  3. 資源限制:posix_setrlimit() 限制文件描述符、內存、CPU
  4. 健康檢查:暴露 HTTP /health 端點或 TCP 探活
  5. 優雅重啟:接收 SIGUSR2 重新加載配置、熱更新代碼

現代替代方案對比

階段目的
第一次 Fork父進程退出,Shell 以為任務結束;子進程繼續運行
setsid()脫離終端,創建新會話
第二次 Fork確保守護進程不是會話首進程,防止意外獲得控制終端
方案優點缺點適用場景
PHP pcntl 守護進程原生、無依賴、完全控制代碼複雜、單進程併發弱、需自行處理信號/僵屍進程學習、簡單服務、嵌入式
Swoole / Workerman高性能異步、多進程、協程、內置 HTTP/WebSocket/TCP需安裝擴展、學習曲線高併發、長連接、微服務、生產首選
ReactPHP / Amp純 PHP 異步、無擴展依賴性能受限於 PHP 引擎不想裝擴展的異步場景
systemd + PHP-FPM標準化、穩定、生態成熟請求響應模式、非長連接傳統 Web 應用

總結

PHP 編寫守護進程核心技術棧:CLI SAPI + pcntl + posix + sockets。雙重 Fork + setsid 是經典 Unix 守護進程模式。現代生產環境強烈建議使用 Swoole 或 Workerman,獲得數量級性能提升和豐富的網絡編程抽象。理解底層原理有助於排查框架層面的疑難雜症。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved