Reputation: 153
I'm using anonymous pipes to send commands between two processes. Usually everything works great but from time to time the command received by the consumer is truncated and only half of it comes through.
This is how I send commands:
AnonymousPipeServerStream pipeServer = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable);
StreamWriterpipeWriter = new StreamWriter(this.pipeServer) { AutoFlush = true };
pipeWriter.WriteLine(command);
and this is how I read them:
AnonymousPipeClientStream pipeClient = new AnonymousPipeClientStream(PipeDirection.In, pipeId);
StreamReader pipeReader = new StreamReader(this.pipeClient);
string command = pipeReader.ReadLine();
The command is actually a small base64-converted pdf file with some additional data. The command written to the pipeWriter has the correct form (at least logs tell us that much) and the command received by the consumer is usually OK. Then, from time to time it's not and for some reason consumer gets only some portion of it.
When we try to send the same command again it will go through. Sending the command again will dispose the old consumer but the producer will stay the same.
Is there any known reason for this situation to occur? Am I missing something obvious?
Upvotes: 4
Views: 515
Reputation: 942267
It is a quirk in the underlying Windows implementation of pipes. It doesn't distinguish between "I closed the pipe because something went wrong" vs "I closed the pipe because I'm done with it". It implements the former, throws away the data in the buffer and thus requires the writer to explicitly make sure that the data that's stored in the pipe buffer made it to the client before it closes the pipe. The native winapi function is FlushFileBuffers().
The .NET wrapper classes could have made that a bit clearer but they didn't. You therefore have to make this explicit as well, getting the FlushFileBuffers() function called requires calling WaitForPipeDrain(). Do this just before you call Close() or Dispose() on your AnonymousPipeServerStream. And don't do it when you shut down the pipe because of an exception.
Upvotes: 3
Reputation: 1624
On writer side you need to call WaitForPipeDrain
before you close the pipe.
Upvotes: 4