php 实现守护进程
PHP 实现守护进程的方法
在 PHP 中实现守护进程(Daemon)通常需要将脚本脱离终端运行,并在后台持续执行。以下是实现守护进程的关键步骤和代码示例:
创建守护进程的基本步骤
脱离终端控制
使用 pcntl_fork 创建子进程,父进程退出,子进程继续运行。这使进程脱离终端控制。
$pid = pcntl_fork();
if ($pid < 0) {
exit('Fork failed');
} elseif ($pid > 0) {
exit(); // 父进程退出
}
创建新会话
通过 posix_setsid 创建新的会话,使进程成为会话组长,脱离终端关联。
if (posix_setsid() === -1) {
exit('Setsid failed');
}
再次 fork 确保非会话组长 某些系统可能会重新获取终端控制权,再次 fork 可避免这种情况。

$pid = pcntl_fork();
if ($pid < 0) {
exit('Second fork failed');
} elseif ($pid > 0) {
exit(); // 父进程退出
}
关闭标准输入输出 守护进程通常不需要标准输入输出,可以关闭这些文件描述符。
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
完整示例代码
<?php
// 第一次 fork
$pid = pcntl_fork();
if ($pid < 0) {
exit('Fork failed');
} elseif ($pid > 0) {
exit(); // 父进程退出
}
// 创建新会话
if (posix_setsid() === -1) {
exit('Setsid failed');
}
// 第二次 fork
$pid = pcntl_fork();
if ($pid < 0) {
exit('Second fork failed');
} elseif ($pid > 0) {
exit(); // 父进程退出
}
// 关闭标准文件描述符
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
// 守护进程主逻辑
while (true) {
// 执行任务代码
file_put_contents('/tmp/daemon.log', date('Y-m-d H:i:s') . " Running\n", FILE_APPEND);
sleep(5);
}
?>
注意事项
信号处理
守护进程需要处理信号,如 SIGTERM 用于正常退出。

pcntl_signal(SIGTERM, function ($signo) {
file_put_contents('/tmp/daemon.log', "Received signal $signo, exiting\n", FILE_APPEND);
exit();
});
日志记录 由于关闭了标准输出,建议将日志写入文件或系统日志。
防止重复运行 使用文件锁或 PID 文件确保只有一个实例运行。
$lockFile = '/tmp/daemon.pid';
if (file_exists($lockFile)) {
$pid = file_get_contents($lockFile);
if (posix_kill($pid, 0)) {
exit('Daemon already running');
}
}
file_put_contents($lockFile, getmypid());
使用第三方库
对于更复杂的守护进程需求,可以考虑使用以下库:
- Symfony Process:提供进程管理功能。
- PEAR System_Daemon:专门用于创建守护进程的库。
- Supervisor:用于管理守护进程的外部工具。
通过以上方法,可以有效地在 PHP 中实现守护进程功能。






