POSIX
函数
- posix_access — 确定文件的可访问性
- posix_ctermid — 获取控制终端的路径名
- posix_eaccess — 确定文件的可访问性
- posix_errno — 别名 posix_get_last_error
- posix_fpathconf — 返回可配置限制的值
- posix_get_last_error — 检索最后一个失败的 posix 函数设置的错误号
- posix_getcwd — 当前目录的路径名
- posix_getegid — 返回当前进程的有效组 ID
- posix_geteuid — 返回当前进程的有效用户 ID
- posix_getgid — 返回当前进程的真实组 ID
- posix_getgrgid — 按组 ID 返回有关组的信息
- posix_getgrnam — 按名称返回有关组的信息
- posix_getgroups — 返回当前进程的组集
- posix_getlogin — 返回登录名
- posix_getpgid — 获取用于作业控制的进程组 ID
- posix_getpgrp — 返回当前进程组标识符
- posix_getpid — 返回当前进程 id
- posix_getppid — 返回父进程标识符
- posix_getpwnam — 按用户名返回有关用户的信息
- posix_getpwuid — 按用户 ID 返回有关用户的信息
- posix_getrlimit — 返回有关系统资源限制的信息
- posix_getsid — 获取进程的当前 sid
- posix_getuid — 返回当前进程的真实用户 ID
- posix_initgroups — 计算组访问列表
- posix_isatty — 确定文件描述符是否为交互式终端
- posix_kill — 向进程发送信号
- posix_mkfifo — 创建 FIFO 特殊文件(命名管道)
- posix_mknod — 创建一个特殊或普通文件 (POSIX.1)
- posix_pathconf — 返回可配置限制的值
- posix_setegid — 设置当前流程的有效 GID
- posix_seteuid — 设置当前进程的有效 UID
- posix_setgid — 设置当前进程的 GID
- posix_setpgid — 为作业控制设置进程组 ID
- posix_setrlimit — 设置系统资源限制
- posix_setsid — 将当前进程设为会话领导者
- posix_setuid — 设置当前进程的 UID
- posix_strerror — 检索与给定 errno 关联的系统错误消息
- posix_sysconf — 返回系统运行时信息
- posix_times — 获取处理时间
- posix_ttyname — 确定终端设备名称
- posix_uname — 获取系统名称
posix_getppid
返回父进程标识符
echo posix_getppid(); // 8259
posix_setsid
PHP: posix_setsid - Manual
proc_open 用于启动外部程序并进行 I/O 通信,而 pcntl (配合 posix_setsid) 用于在 同一 PHP 脚本内部创建并发子进程,并将其后台化为守护进程。
// 确保扩展已加载
if (!extension_loaded('pcntl') || !extension_loaded('posix')) {
die("PCNTL and POSIX extensions are required.\n");
}
// 1. 第一次 fork:创建子进程
$pid = pcntl_fork();
if ($pid === -1) {
// fork 失败
die("Could not fork.\n");
} elseif ($pid > 0) {
// 父进程退出:这是关键,它保证了子进程不会是进程组的领导者
// 这样子进程才能成功调用 posix_setsid()
exit(0);
}
// ----------------------------------------------------
// 接下来是子进程 (Daemon) 的代码
// ----------------------------------------------------
// 2. 调用 posix_setsid():创建一个新的会话
$sid = posix_setsid();
if ($sid < 0) {
// setsid 失败
die("Could not set session leader.\n");
}
// 此时:
// - 当前进程是新会话 (Session) 的领导者。
// - 当前进程是新进程组 (Process Group) 的领导者。
// - 当前进程 脱离了 控制终端 (Controlling Terminal)。
// 3. 更改当前工作目录,避免阻止卸载文件系统 (可选,但推荐)
chdir('/');
// 4. 关闭标准文件描述符, 确保进程不会因为终端 I/O 而阻塞 (可选,但推荐)
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
$stdin = fopen('/dev/null', 'r');
$stdout = fopen('/dev/null', 'w');
$stderr = fopen('/dev/null', 'w');
// 5. 守护进程主循环
echo "Daemon started with PID: " . posix_getpid() . ", Session ID: " . $sid . "\n";
// 注意:如果在终端中运行这段代码,echo 可能会丢失,因为 STDOUT 已被关闭或重定向
// 实际的守护进程应该使用日志文件。
while (true) {
// 守护进程执行写入日志
file_put_contents('/tmp/setsid.log', 'daemon working...', FILE_APPEND);
sleep(5); // 每 5 秒执行一次任务
}
运行和验证
- 运行
php setsid.php
命令行会立即返回。
2. 验证后台运行(检查 PPID 是否为 1,表示已成功后台化。)
ps -ef | grep 'setsid.php'
501 79303 1 0 5:07下午 ?? 0:00.00 php setsid.php
- 验证日志(检查日志文件是否每 5 秒更新一次。)
tail -f /tmp/setsid.log
daemon working...
- 停止
kill <PID> # 使用上面 ps 命令查到的 PID
pkill -f 'setsid.php'