管道是内核维护的单向字节流缓冲区,读端和写端通过文件描述符访问。它适合 shell 命令串联或具有亲缘关系的进程通信,数据不需要落盘。它的简单也有边界:管道传的是连续字节,不会替应用保存“这一段是第几条消息”。
创建 pipe→写端写入内核缓冲区→等待的读端被唤醒→读端取走字节流
读端 fd读取字节流,所有写端关闭后会读到 EOF。写端 fd写入缓冲区;没有读端时会得到 SIGPIPE 或 EPIPE。内核缓冲容量有限,满时阻塞或返回 EAGAIN,取决于阻塞模式。PIPE_BUF不超过该阈值的一次写入可避免与其他写者交错。消息边界read 可返回任意长度,协议需要自行处理粘连和拆分。关闭无用端fork 后必须关闭不使用的端点,否则 EOF 和 SIGPIPE 都会失真。
用长度或分隔符定义消息边界
若要通过管道传递多条记录,应用层需要使用固定长度、长度前缀或安全的分隔协议。一次 write() 不一定对应一次 read();读者可能得到半条记录,也可能一次拿到多条。PIPE_BUF 原子性只解决多个写者交错的问题,不会自动给读者恢复消息边界。
EOF 和 SIGPIPE 常常暴露 fd 泄漏
调用 fork() 后,父子进程都拥有两端 fd。每个进程都应尽早关闭不使用的一端,否则读者会因为仍有隐藏写端而永远等不到 EOF,写者也不会及时收到没有读者的错误。调试管道卡住时,先检查进程实际持有哪些 fd,往往比盯着读写循环更有效。