views:

165

answers:

3

I have created a named pipe with following flags:

  • PIPE_ACCESS_DUPLEX - both side read/write access
  • PIPE_TYPE_MESSAGE - Message type read
  • PIPE_WAIT - blocking read\write

From the server side I am calling ConnectNamedPipe and waiting for the clients to connect.

From the client side I am calling CallNamedPipe to connect to server and write data of length N.

On the server side:

  • After the client connects, PeekNamedPipe is called to get the length of the buffer to allocate to read the data buffer.
  • After getting the exact buffer size (N), I am allocating the buffer of length N and calling ReadFile to read the data from Pipe.

Problem:

  • The issue is that -- on Single processor machines the PeekNamedPipe API returns the buffer length as 0. Due to this later ReadFile fails.
  • after some investigation I could find that due to some race condition , PeekNamedPipe API gets called even before data is put onto the Pipe by the client.
  • Any idea how to solve this race condition ? I need to call PeekNamedPipe to get the buffer size and PeekNamedPipe cannot be called before the data is available.

I thought of introducing custom header to indicate the buffer length in the message itself but this sounds lot of changes.

Is there any better and reliable way to get the length of the data to be read from pipe ?

A: 

Having a packet size in the header is a good idea in any case, making the protocol less dependent on transport layer. Alternatively, if the client sends data and closes the pipe you can accumulate into buffer with ReadFile until EOF.

ygrek
+1  A: 

It sounds like you want Aynschronous I/O. Just let Windows notify you when data is available, and peek at that moment.

MSalters
+5  A: 

There are a large number of race conditions you can get with named pipes. You have to deal with them in your code. Possibilities:

  • ConnectNamedPipe() on the server side may return ERROR_PIPE_CONNECTED if the client managed to connect right after the CreateNamedPipe() call. Just treat it as connected.
  • WaitNamedPipe on client side does not set the error if it timed out. Assume a timeout.
  • CreateFile() on client side may return ERROR_PIPE_BUSY if another client managed to grab the pipe first, even after a successful WaitNamedPipe() call. Go back to WaitNamedPipe state.
  • FlushFileBuffers() may return ERROR_PIPE_NOT_CONNECTED if the client already saw the message and closed the pipe. Ignore that.
  • An overlapped ReadFile() call may complete immediately and not return ERROR_IO_PENDING. Consider the read completed.
  • PeekNamedPipe() may return 0 if the server has not written to the pipe yet. Sleep(1) and repeat.
Hans Passant