windows命名管道需正确设置dwopenmode和dwpipemode、规范命名格式并循环调用connectnamedpipe;linux fifo需按序打开读写端,无消息边界且易阻塞,跨平台需注意缓冲差异与错误码含义。

Windows 上用 CreateNamedPipe 创建服务端管道
命名管道在 Windows 下是可靠、双向的本地 IPC 机制,但CreateNamedPipe 的参数稍不注意就返回 INVALID_HANDLE_VALUE,常见原因是 dwOpenMode 和 dwPipeMode 搭配错误。
实操建议:
立即学习“C++免费学习笔记(深入)”;
-
dwOpenMode至少要含PIPE_ACCESS_DUPLEX(双向)或PIPE_ACCESS_INBOUND(只读),不能只写GENERIC_READ | GENERIC_WRITE—— 这是文件句柄逻辑,管道不认 -
dwPipeMode必须用PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT组合,否则客户端调用WriteFile可能阻塞或失败 - 名字格式必须是
\\.\pipe\MyPipeName,开头双反斜杠 +.+pipe是硬性要求,少一个字符就ERROR_FILE_NOT_FOUND - 服务端需在循环中调用
ConnectNamedPipe,它会阻塞直到客户端连接;若想非阻塞,得先设FILE_FLAG_OVERLAPPED并配套用GetOverlappedResult
Linux 下用 mkfifo 和 open 模拟命名管道
Linux 没有原生“命名管道服务端/客户端”概念,mkfifo 创建的是一个特殊文件节点,通信靠两个进程分别以不同模式打开它——这点和 Windows 完全不同,直接照搬 Windows 思路必出错。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 先执行
mkfifo /tmp/my_pipe,再由服务端用open("/tmp/my_pipe", O_RDONLY)打开读端,客户端用open("/tmp/my_pipe", O_WRONLY)打开写端;顺序不能反,否则open会阻塞直到对方也打开 - 若任一方只以
O_WRONLY打开而无对应O_RDONLY,open会永久挂起,调试时容易误判为死锁 - 消息边界不保留:Linux FIFO 是字节流,
write多次小数据可能被read一次合并读出,如需消息分界,得自己加长度头或分隔符 - 不支持跨主机,且无法像 Windows 那样设置安全描述符或连接超时
跨平台收发数据时,ReadFile / WriteFile 和 read / write 的缓冲行为差异
Windows 管道默认启用缓冲,Linux FIFO 则完全无缓冲。这意味着同样发 1KB 数据,在 Windows 上可能还没真正落到底层驱动就被函数返回了,而在 Linux 上 write 返回即表示内核已接收,但没对方 read 就会阻塞后续 write。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- Windows 下用
SetNamedPipeHandleState控制缓冲区大小(lpOutBufferSize),避免大消息被截断;Linux 下只能靠fcntl(fd, F_SETPIPE_SZ, size)(需 root 或 CAP_SYS_RESOURCE)调大内核 FIFO 缓冲,但上限通常 64KB - 双方都应检查返回值:
ReadFile返回FALSE不一定失败,得看GetLastError()是否为ERROR_MORE_DATA;read返回 0 表示写端已关闭,不是错误 - 不要假设“发完就立刻能收”,尤其在调试时加
std::this_thread::sleep_for掩盖同步问题,真实环境会暴露竞态
调试时遇到 ERROR_PIPE_BUSY 或 EAGAIN 怎么办
ERROR_PIPE_BUSY(Windows)和 EAGAIN(Linux)表面都是“忙”,但成因完全不同:前者是服务端还没调用 ConnectNamedPipe 或已有连接未断开,后者是 Linux FIFO 写端打开时无读端匹配,或读端已关闭但写端还在发。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- Windows 下遇到
ERROR_PIPE_BUSY,先调WaitNamedPipe等待管道就绪,再重试CreateFile;别直接循环重试CreateFile,可能触发系统限制 - Linux 下
open(O_WRONLY)返回EAGAIN,说明当前无读端,此时要么改用O_WRONLY | O_NONBLOCK避免阻塞,要么确保服务端先启动并open(O_RDONLY) - 用
Process Explorer(Win)或lsof | grep pipe(Linux)查管道句柄是否残留,重复测试时忘记CloseHandle或close会导致后续创建失败
命名管道最麻烦的从来不是 API 调用本身,而是两端生命周期管理——哪边先启、哪边先关、异常退出后句柄是否清理干净,这些细节在日志里几乎不报错,只能靠 handle 或 lsof 手动确认。










