我创建了一个带有以下标志的命名管道:
- PIPE_ACCESS_DUPLEX - 双方读/写访问权限
- PIPE_TYPE_MESSAGE - 已读消息类型
- PIPE_WAIT - 阻塞读\写
我从服务器端调用 ConnectNamedPipe并等待客户端连接。
我从客户端调用 CallNamedPipe连接服务器并写入长度为N的数据。
在服务器端:
- 客户端连接后,PeekNamedPipe被调用以获取分配给读取数据缓冲区的缓冲区的长度。
- 获得确切的缓冲区大小 (N) 后,我分配长度为 N 的缓冲区并调用 ReadFile从 Pipe 读取数据。
问题:
- 问题是——在单处理器机器上,PeekNamedPipe API 将缓冲区长度返回为 0。因此,稍后的 ReadFile 失败。
- 经过一些调查,我发现由于某些竞争条件,甚至在客户端将数据放入管道之前,PeekNamedPipe API 就被调用了。
- 知道如何解决这个竞争条件吗?我需要调用 PeekNamedPipe 来获取缓冲区大小,并且在数据可用之前无法调用 PeekNamedPipe。
我想引入自定义 header 来指示消息本身的缓冲区长度,但这听起来有很多变化。
有没有更好更可靠的方法来获取要从管道读取的数据的长度?
最佳答案
您可以通过命名管道获得大量竞争条件。您必须在代码中处理它们。可能性:
- 如果客户端在 CreateNamedPipe() 调用后成功连接,服务器端的 ConnectNamedPipe() 可能会返回 ERROR_PIPE_CONNECTED。只需将其视为已连接即可。
- 如果超时,客户端的 WaitNamedPipe 不会设置错误。假设超时。
- 如果另一个客户端设法首先获取管道,即使在成功调用 WaitNamedPipe() 之后,客户端的 CreateFile() 也可能返回 ERROR_PIPE_BUSY。回到 WaitNamedPipe 状态。
- 如果客户端已经看到消息并关闭了管道,FlushFileBuffers() 可能会返回 ERROR_PIPE_NOT_CONNECTED。忽略它。
- 重叠的 ReadFile() 调用可能会立即完成并且不会返回 ERROR_IO_PENDING。考虑阅读完成。
- 如果服务器还没有写入管道,PeekNamedPipe() 可能会返回 0。 sleep (1) 并重复。
关于c++ - 如何获取命名管道中要(可靠地)读取的数据长度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2084535/