本文提供一個完整的 PHP 多進程示例,結合 pcntl_fork、信號處理與非阻塞 Socket,實現一個將外部連接轉發至內部 VNC 服務的守護進程。代碼涵蓋進程分離、信號捕獲、雙向數據透傳、資源清理等核心環節,可作為 PHP CLI 多進程網絡編程的參考模板。
accept 連接,fork 子進程處理,自身持續監聽。SIGTERM/SIGTRAP 優雅關閉,SIGCHLD 回收子進程避免殭屍。$pid = pcntl_fork();
if ($pid == -1) die("could not fork");
if ($pid) die("Daemon PID:$pid\n"); // 父進程退出,子進程成為孤兒進程由 init 收養
if (!posix_setsid()) die("could not detach from terminal\n"); // 脫離終端
declare(ticks = 1); // 必須開啟才能註冊信號處理器
pcntl_signal(SIGTERM, "SignalFunction");
pcntl_signal(SIGTRAP, "SignalFunction");
pcntl_signal(SIGCHLD, "SignalFunction");
$serverSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($serverSocket, 0, $ServerPort); // 0 監聽所有接口
socket_listen($serverSocket);
socket_set_nonblock($serverSocket); // 非阻塞
unset($PID); // 標記無活躍子進程
while (true) {
sleep(1); // 輪詢間隔
$connected = @socket_accept($serverSocket);
if ($connected !== false) {
$PID = pcntl_fork();
if ($PID == -1) die("could not fork");
if ($PID) continue; // 父進程繼續監聽
// 子進程處理連接
ProcessSocket($connected);
DestroySocket();
exit(0);
}
}
function ProcessSocket($serverSocket) {
global $RemoteSocket, $IP, $Port;
declare(ticks = 1);
pcntl_signal(SIGTERM, "ChildSignalFunction");
pcntl_signal(SIGTRAP, "ChildSignalFunction");
$RemoteSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
@socket_connect($RemoteSocket, $IP, $Port);
socket_set_nonblock($RemoteSocket);
socket_set_nonblock($serverSocket);
while (true) {
$recv = @socket_read($serverSocket, 4096, PHP_BINARY_READ);
$remoteRecv = @socket_read($RemoteSocket, 4096, PHP_BINARY_READ);
// 處理斷開、無數據、數據轉發邏輯...
// 關鍵:非阻塞模式下 false 表示無數據,'' 表示連接關閉
// 使用 usleep(100000) 避免空轉佔用 CPU
}
}
function DestroySocket() {
global $ServerSocket, $RemoteSocket;
if ($RemoteSocket) {
@socket_shutdown($RemoteSocket, 2);
socket_clear_error($RemoteSocket);
socket_close($RemoteSocket);
}
@socket_shutdown($ServerSocket, 2);
socket_clear_error($ServerSocket);
socket_close($ServerSocket);
}
function SignalFunction($sig) {
global $PID;
switch ($sig) {
case SIGTERM: case SIGTRAP:
if ($PID) { posix_kill($PID, SIGTERM); pcntl_wait($status); }
DestroySocket(); exit(0);
case SIGCHLD:
unset($PID); pcntl_wait($status); break;
}
}
pcntl、sockets 擴展(僅 CLI 模式可用)。完整代碼已包含錯誤處理、非阻塞輪詢、優雅關閉等工程化細節,可直接作為 PHP 多進程網絡編程的起點。