php实现守护进程
PHP 实现守护进程的方法
在 PHP 中实现守护进程(Daemon)通常需要将脚本脱离终端运行,并在后台持续执行。以下是实现守护进程的关键步骤。
使用 pcntl_fork 创建子进程
通过 pcntl_fork 函数创建子进程,父进程退出,子进程继续运行。这是实现守护进程的基础。
$pid = pcntl_fork();
if ($pid == -1) {
exit("Could not fork");
} elseif ($pid) {
exit(); // 父进程退出
}
调用 posix_setsid 创建新会话
子进程调用 posix_setsid 创建新的会话,脱离终端控制。
if (posix_setsid() == -1) {
exit("Could not detach from terminal");
}
关闭标准输入输出
守护进程通常不需要标准输入输出,可以关闭或重定向到 /dev/null。
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
设置工作目录
将工作目录切换到根目录或其他安全目录,避免占用挂载点。
chdir('/');
处理信号
守护进程需要处理信号,例如 SIGTERM 用于优雅退出。
pcntl_signal(SIGTERM, function($signo) {
exit("Received signal $signo, exiting");
});
循环执行任务
守护进程通常包含一个无限循环,执行周期性任务。
while (true) {
// 执行任务逻辑
sleep(1); // 避免 CPU 过度占用
pcntl_signal_dispatch(); // 处理信号
}
完整的守护进程示例代码
<?php
// 创建子进程
$pid = pcntl_fork();
if ($pid == -1) {
exit("Could not fork");
} elseif ($pid) {
exit(); // 父进程退出
}
// 创建新会话
if (posix_setsid() == -1) {
exit("Could not detach from terminal");
}
// 关闭标准输入输出
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
// 设置工作目录
chdir('/');
// 处理信号
pcntl_signal(SIGTERM, function($signo) {
exit("Received signal $signo, exiting");
});
// 主循环
while (true) {
// 执行任务逻辑
file_put_contents('/tmp/daemon.log', date('Y-m-d H:i:s') . PHP_EOL, FILE_APPEND);
sleep(5);
pcntl_signal_dispatch();
}
?>
使用 nohup 或 screen 运行守护进程
如果不想修改代码,可以通过外部工具实现守护进程效果。
nohup php daemon.php > /dev/null 2>&1 &
或使用 screen:

screen -dmS daemon php daemon.php
注意事项
- 确保 PHP 安装了
pcntl和posix扩展。 - 避免在循环中占用过多 CPU,使用
sleep或usleep控制频率。 - 考虑使用
syslog记录日志,避免文件权限问题。 - 对于长时间运行的进程,注意内存泄漏问题。






