Swoole的Process管道通信底层实际使用Unix Socket而非Linux pipe,通过socketpair(AF_UNIX, SOCK_STREAM/SOCK_DGRAM, 0, fds)创建双向文件描述符,支持超时、阻塞控制及流式或数据报式通信。

管道底层不是 Linux pipe,而是 Unix Socket
Swoole 的 swoole_process 管道通信,名字叫“pipe”,但实际不调用 pipe() 或 mkfifo() 系统调用。从 1.7.x 开始,底层统一使用 socketpair(AF_UNIX, SOCK_STREAM, 0, fds)(或 SOCK_DGRAM)创建一对双向 Unix Socket 文件描述符。这意味着:它本质是内核内存通信,零磁盘 IO,也不经过 VFS 层。
这种设计带来两个关键影响:
- 父子进程共享同一对 socket fd,天然支持双向通信(而原生匿名 pipe 是单向的)
- 因为基于 socket,所以能复用超时、阻塞/非阻塞、
select/poll等机制,比传统 pipe 更可控
STREAM 和 DGRAM 两种模式决定数据边界处理方式
$create_pipe 参数传 1 或 2,分别对应 SOCK_STREAM 和 SOCK_DGRAM 类型。这不是可有可无的配置,直接关系到你是否要自己拆包:
-
SOCK_STREAM(默认):流式,write("a"); write("b")可能在一次read(1024)中被合并成"ab",没有消息边界 -
SOCK_DGRAM($create_pipe = 2):数据报式,每次write()是一个独立数据单元,read()会按原长度返回(不超过缓冲区),天然保序、保边界
如果你在子进程中 echo "hello" 并依赖父进程 read() 拿到完整字符串,又没开 $redirect_stdin_stdout,那必须用 SOCK_DGRAM,否则可能读到截断或拼接的数据。
$redirect_stdin_stdout 会强制覆盖管道类型
这个参数看似只是重定向 IO,但它会悄悄改掉你的通信契约:
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 只要设为
true,无论你传$create_pipe = 0还是2,Swoole 都会强制创建SOCK_STREAM管道 - 子进程里所有
echo、print、var_dump输出都会写入管道;fgets(STDIN)会从管道读,而非终端 - 此时你无法用
SOCK_DGRAM保证单次输出的原子性——比如echo "OK\n"; echo "ERR\n"可能被父进程一次read()全部拿到
所以,如果需要精确控制每条消息的边界,不要开启 $redirect_stdin_stdout,手动调用 $process->write() 发送二进制或 JSON 封包更可靠。
管道生命周期由 Process 对象绑定,不是靠 fork 时机
很多人误以为管道在 fork() 时自动继承,其实 Swoole 的管道是 swoole_process 实例的成员变量 pipe,其 fd 在构造函数中创建,在对象析构时自动 close()。
这意味着:
- 父进程
unset($process)或作用域结束 → 管道关闭 → 子进程read()会立刻返回 0(EOF) - 子进程退出后,父进程未及时
wait(),管道 fd 仍有效,但再write()会触发BROKEN PIPE错误(swoole_errno === 32) - 多个子进程共用同一个父进程管道?不行。每个
swoole_process实例独占一对 socket fd,不能复用
真正容易被忽略的是:管道关闭不等于子进程死亡。子进程可能还在跑,但管道已断,后续 read() 不会阻塞,而是立即失败。这时候得靠信号或 pcntl_waitpid() 做最终状态确认。

















