windows命名管道默认为单向,双向通信需配对使用两个独立管道实例,服务端用pipe_access_inbound/outbound分别创建请求与响应管道,客户端通过createfile分别连接,且必须启用消息模式或自定义长度头以确保消息边界完整。

Windows上用CreateNamedPipe创建可读写管道
CreateNamedPipe 默认创建的是单向管道(只读或只写),想跨进程双向通信,不能靠单个管道实例“全双工”,得用两个命名管道:一个供客户端写、服务端读;另一个反过来。Windows 命名管道本身不支持同一句柄同时 ReadFile 和 WriteFile(除非用 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE 配合异步 I/O,但语义仍是单向流)。实际做法是服务端开一对命名管道(如 "\.pipemyapp-req" 和 "\.pipemyapp-res"),客户端按约定连接对应端。
- 服务端调用
CreateNamedPipe时,dwOpenMode设为PIPE_ACCESS_INBOUND或PIPE_ACCESS_OUTBOUND,别用PIPE_ACCESS_DUPLEX期望双向——它只表示“服务端可读可写”,但客户端仍只能单向连接 - 客户端必须用
CreateFile分别打开两个不同名字的管道,不能复用同一个名字的句柄做读写 - 每个管道句柄建议设
FILE_FLAG_OVERLAPPED,否则ReadFile/WriteFile会阻塞,一端没数据时整个线程卡住
客户端如何避免ConnectNamedPipe失败或超时
ConnectNamedPipe 只能在服务端调用,客户端用 CreateFile 连接。常见错误是客户端调用后立刻 WriteFile,但服务端还没来得及 ConnectNamedPipe,导致写入失败并返回 ERROR_PIPE_NOT_CONNECTED。
- 客户端
CreateFile时,dwFlagsAndAttributes必须含FILE_ATTRIBUTE_NORMAL(不能是FILE_FLAG_DELETE_ON_CLOSE等冲突标志) - 服务端在
CreateNamedPipe后,要立即调用ConnectNamedPipe并等待完成(同步模式下会阻塞,直到客户端连接;异步需配OVERLAPPED) - 若服务端启动晚于客户端,客户端
CreateFile会失败,错误码是ERROR_FILE_NOT_FOUND;此时应循环重试,每次间隔几百毫秒,别直接退出
消息边界怎么保持不粘包、不截断
命名管道默认是字节流(PIPE_TYPE_BYTE),WriteFile 发 100 字节,ReadFile 可能只收到前 30 字节——没有内置消息帧。必须自己处理协议。
完整流程:Reddit 痛点扫描 → 聚类 → 构建 pip 可安装的 CLI 工具 → 推送到 GitHub。使用此模式已交付 5 款工具,经验证 343 条痛点。
- 用
PIPE_TYPE_MESSAGE模式(创建时设PIPE_READMODE_MESSAGE)能让每次WriteFile当作一条独立消息,ReadFile会等整条消息收完才返回,但要求两端都用该模式,且单条消息不能超过 64KB(内核限制) - 更通用的做法是自定义头:每个包前 4 字节存
uint32_t表示有效载荷长度,接收方先读 4 字节,再循环读够指定字节数 - 别依赖
ReadFile的lpNumberOfBytesRead一次读完——它只反映本次系统调用实际搬运的字节数,不是逻辑消息长度
服务端如何安全处理多个客户端并发连接
CreateNamedPipe 的 nMaxInstances 参数控制最多几个客户端能同时连接。设为 1 就只能串行,设为 PIPE_UNLIMITED_INSTANCES(=255)也受系统资源限制。
- 每次
ConnectNamedPipe成功后,服务端应把新得到的管道句柄交给独立线程或 I/O 完成端口处理,原监听线程立刻回到ConnectNamedPipe等下一个客户端 - 忘记对句柄调用
CloseHandle是常见内存泄漏源;尤其在异常路径(如ReadFile返回 0 表示客户端断开)中必须清理 - 多客户端共用同一管道名时,服务端无法区分是谁发来的数据——身份识别得靠应用层协议(比如首包发个 client_id 字符串)
跨进程双向通信真正麻烦的不是建管道,而是谁先发、谁等谁、断连后怎么重置状态、缓冲区怎么管理。这些细节不写进协议设计里,跑两天就出现半包、死锁或句柄耗尽。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










