Windows下CreateNamedPipe创建服务端管道需严格配置参数:dwOpenMode须含PIPE_ACCESS_DUPLEX等访问模式及FILE_FLAG_OVERLAPPED;dwPipeMode推荐PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT;nMaxInstances设为PIPE_UNLIMITED_INSTANCES;lpSecurityAttributes为nullptr时仅限同用户访问。

Windows 下用 CreateNamedPipe 创建服务端管道
命名管道在 Windows 上是内核对象,服务端必须先创建,客户端才能连接。关键不是“怎么建”,而是建的时候参数稍有偏差就导致客户端 ConnectNamedPipe 失败或阻塞超时。
常见错误现象:ConnectNamedPipe 返回 false,GetLastError() 是 5(拒绝访问)或 231(所有实例都忙);或者调用成功但后续读写卡住。
-
dwOpenMode至少要含PIPE_ACCESS_DUPLEX(双向)或PIPE_ACCESS_INBOUND/PIPE_ACCESS_OUTBOUND,别漏掉FILE_FLAG_OVERLAPPED(否则同步模式下容易死锁) -
dwPipeMode推荐用PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT:消息模式能保整包边界,PIPE_WAIT避免客户端未连时ReadFile立即返回失败 - 实例数(
nMaxInstances)设为PIPE_UNLIMITED_INSTANCES更稳妥,除非明确要限制并发连接 - 安全描述符(
lpSecurityAttributes)若为nullptr,默认只允许同用户进程访问;跨用户或服务场景需显式构造SECURITY_DESCRIPTOR
客户端用 CreateFile 连接命名管道
客户端不调用专用“连接函数”,而是把管道当文件打开——这点容易误解。路径格式、重试逻辑和超时控制是成败关键。
常见错误现象:CreateFile 返回 INVALID_HANDLE_VALUE,GetLastError() 是 2(找不到文件)或 109(管道已结束)。
立即学习“C++免费学习笔记(深入)”;
- 路径必须是
\\.\pipe\{name}格式,开头四个反斜杠不能少,也不能写成正斜杠或单斜杠 - 用
OPEN_EXISTING打开,dwCreationDisposition别误填CREATE_ALWAYS等非法值 - 服务端尚未创建管道时,
CreateFile默认立即失败;加FILE_FLAG_OVERLAPPED后可用WaitForSingleObject等待,或循环重试(建议带sleep(100)防爆 CPU) - 若服务端设置为
PIPE_WAIT,客户端CreateFile会阻塞直到服务端调用ConnectNamedPipe;反之若服务端是PIPE_NOWAIT,客户端必须确保服务端已就绪
读写时用 ReadFile/WriteFile 处理消息边界
命名管道支持字节流和消息两种模式,但 C++ 项目里多数需要保消息完整性(比如发一个结构体、一段 JSON),这时必须匹配服务端的 PIPE_TYPE_MESSAGE 模式,否则 ReadFile 可能只读到半条消息。
常见错误现象:客户端发了 100 字节,服务端 ReadFile 只读到 32 字节就返回;或多次 WriteFile 被合并成一次到达。
- 服务端创建时用了
PIPE_TYPE_MESSAGE,客户端也必须以消息模式读——即服务端调用ReadFile前,确保管道句柄处于消息读取态(通常靠创建时指定) -
ReadFile的lpNumberOfBytesRead参数必须检查,不能假设一次读完全部数据;返回 0 表示对方已关闭连接 - 发送结构体时,不要直接传
sizeof(MyStruct)给WriteFile,要确认结构体没被编译器填充干扰(加#pragma pack(1)或用static_assert校验大小) - 异步 I/O(
FILE_FLAG_OVERLAPPED)下,ReadFile可能返回FALSE且GetLastError() == ERROR_IO_PENDING,此时需用GetOverlappedResult或 I/O 完成端口收结果
Linux 下用 mkfifo + open 替代(POSIX 命名管道)
Linux 没有 Windows 那套 API,命名管道本质是特殊文件,行为差异大:没有“实例数”概念,没有消息模式,且首次 open 会阻塞直到对方以相反权限打开。
常见错误现象:open 卡死;read 返回 0(被当成 EOF);多客户端写入时数据混杂。
- 先用
mkfifo("/tmp/my_pipe", 0666)创建 FIFO 文件,权限位影响后续open是否成功(尤其跨用户时) - 服务端通常
open("/tmp/my_pipe", O_RDONLY),客户端open("/tmp/my_pipe", O_WRONLY);顺序反了就会阻塞 - FIFO 是字节流,无消息边界,发结构体需自行加长度头或分隔符;
read可能返回任意长度(1~PIPE_BUF,通常是 4096),必须循环读满预期字节数 - 服务端
read返回 0 表示所有写端已关闭,不是错误;若需持续通信,客户端不能频繁close写端,否则服务端会退出读循环
Windows 和 Linux 的命名管道根本不是同一套机制,强行封装成统一接口容易踩坑。跨平台项目建议用 socketpair 或第三方库(如 Boost.Iostreams),而不是硬套命名管道语义。


















