POSIX

函数

  1. posix_access — 确定文件的可访问性
  2. posix_ctermid — 获取控制终端的路径名
  3. posix_eaccess — 确定文件的可访问性
  4. posix_errno — 别名 posix_get_last_error
  5. posix_fpathconf — 返回可配置限制的值
  6. posix_get_last_error — 检索最后一个失败的 posix 函数设置的错误号
  7. posix_getcwd — 当前目录的路径名
  8. posix_getegid — 返回当前进程的有效组 ID
  9. posix_geteuid — 返回当前进程的有效用户 ID
  10. posix_getgid — 返回当前进程的真实组 ID
  11. posix_getgrgid — 按组 ID 返回有关组的信息
  12. posix_getgrnam — 按名称返回有关组的信息
  13. posix_getgroups — 返回当前进程的组集
  14. posix_getlogin — 返回登录名
  15. posix_getpgid — 获取用于作业控制的进程组 ID
  16. posix_getpgrp — 返回当前进程组标识符
  17. posix_getpid — 返回当前进程 id
  18. posix_getppid — 返回父进程标识符
  19. posix_getpwnam — 按用户名返回有关用户的信息
  20. posix_getpwuid — 按用户 ID 返回有关用户的信息
  21. posix_getrlimit — 返回有关系统资源限制的信息
  22. posix_getsid — 获取进程的当前 sid
  23. posix_getuid — 返回当前进程的真实用户 ID
  24. posix_initgroups — 计算组访问列表
  25. posix_isatty — 确定文件描述符是否为交互式终端
  26. posix_kill — 向进程发送信号
  27. posix_mkfifo — 创建 FIFO 特殊文件(命名管道)
  28. posix_mknod — 创建一个特殊或普通文件 (POSIX.1)
  29. posix_pathconf — 返回可配置限制的值
  30. posix_setegid — 设置当前流程的有效 GID
  31. posix_seteuid — 设置当前进程的有效 UID
  32. posix_setgid — 设置当前进程的 GID
  33. posix_setpgid — 为作业控制设置进程组 ID
  34. posix_setrlimit — 设置系统资源限制
  35. posix_setsid — 将当前进程设为会话领导者
  36. posix_setuid — 设置当前进程的 UID
  37. posix_strerror — 检索与给定 errno 关联的系统错误消息
  38. posix_sysconf — 返回系统运行时信息
  39. posix_times — 获取处理时间
  40. posix_ttyname — 确定终端设备名称
  41. 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 秒执行一次任务
}

运行和验证

  1. 运行
php setsid.php

命令行会立即返回。
2. 验证后台运行(检查 PPID 是否为 1,表示已成功后台化。)

ps -ef | grep 'setsid.php'
501 79303     1   0  5:07下午 ??         0:00.00 php setsid.php
  1. 验证日志(检查日志文件是否每 5 秒更新一次。)
tail -f /tmp/setsid.log
daemon working...
  1. 停止
kill <PID> # 使用上面 ps 命令查到的 PID
pkill -f 'setsid.php'