如何在命名管道中获取(可靠)读取数据的长度?

时间:2010-01-18 07:42:43

标签: c++ windows winapi named-pipes

我创建了一个带有以下标志的命名管道:

  • PIPE_ACCESS_DUPLEX - 双方读/写访问
  • PIPE_TYPE_MESSAGE - 消息类型已读
  • PIPE_WAIT - 阻止read \ write

从服务器端我正在调用ConnectNamedPipe并等待客户端连接。

从客户端我调用CallNamedPipe连接到服务器并写入长度为N的数据。

在服务器端:

  • 客户端连接后,调用PeekNamedPipe以获取要分配的缓冲区长度以读取数据缓冲区。
  • 在获得确切的缓冲区大小(N)后,我分配长度为N的缓冲区并调用ReadFile来从Pipe中读取数据。

问题:

  • 问题在于 - 在单处理器计算机上,PeekNamedPipe API将缓冲区长度返回为0.因此后来的ReadFile失败。
  • 经过一番调查后,我发现由于某些竞争条件,PeekNamedPipe API甚至在客户端将数据放入Pipe之前就会被调用。
  • 知道如何解决这种竞争条件吗?我需要调用PeekNamedPipe来获取缓冲区大小,并且在数据可用之前无法调用PeekNamedPipe。

我想过引入自定义标头来指示消息本身的缓冲区长度,但这听起来很多变化。

有没有更好更可靠的方法来获取从管道中读取数据的长度?

3 个答案:

答案 0 :(得分:6)

命名管道可以获得大量的竞争条件。您必须在代码中处理它们。可能性:

    如果客户端在CreateNamedPipe()调用之后立即成功连接,则服务器端的
  • ConnectNamedPipe()可能会返回ERROR_PIPE_CONNECTED。只需将其视为已连接。
  • 客户端的
  • WaitNamedPipe如果超时则不会设置错误。假设超时。
  • 客户端的
  • CreateFile()可能会返回ERROR_PIPE_BUSY,如果另一个客户端设法首先获取管道,即使在成功的WaitNamedPipe()调用之后也是如此。回到WaitNamedPipe状态。
  • 如果客户端已经看到该消息并关闭了管道,则FlushFileBuffers()可能会返回ERROR_PIPE_NOT_CONNECTED。忽略这一点。
  • 重叠的ReadFile()调用可能会立即完成,而不会返回ERROR_IO_PENDING。考虑阅读已完成。
  • 如果服务器尚未写入管道,则PeekNamedPipe()可能返回0。睡觉(1)并重复。

答案 1 :(得分:1)

听起来你想要Aynschronous I / O.只需让Windows在数据可用时通知您,然后查看当天。

答案 2 :(得分:0)

在任何情况下,在头中都有一个数据包大小是一个好主意,使协议更少依赖于传输层。 或者,如果客户端发送数据并关闭管道,则可以使用ReadFile累积到缓冲区中,直到EOF。