and this is the client server for pipe-communicating solutiuon. But I need the server to write messages asynchronously and client to read them whenever they pop up, also asynchronously. How can I achieve this? There is number of samples but most of them consider client writing to server and i'm not sure how to achieve my goal, especially with my already-written code...

Sounds to me like you need two clients and two servers.
– RotemSep 9 '13 at 7:26

why you think so? I just need the server to write into pipe and client to read from it, but i don't want it to bee looped, so async method sounds like a better idea. But i'm not sure how to implement BeginWrite in server and BeginRead in client.
– user1013607Sep 9 '13 at 7:31

Is there a particular reason you aren't using WCF for this?
– Giles MorrisSep 9 '13 at 8:42

It seems to me that the client and server roles may be reversed: typically the server role responds to events from the client role. Maybe the client (as shown) should be opening a pipe with PipeDirection.In and the server (as shown) should open and write into the pipe when the server generates an event.
– psaxtonOct 21 '14 at 20:59

2 Answers
2

First, you don't need two pipes.. You can write/read on both ends of a single named pipe, and it won't get the messages or the ordering, confused. Nor will it get jammed up. Both sides can write as fast as they want, and read whenever they want, as long as you obey basic pipe rules.

Second, you should be using Message mode, not Byte mode, or it might lump sent or read messages together into one buffer.

Third, I'm pretty sure if you use Message-based Pipes, not Byte, you don't need to call WaitForPipeDrain or Flush. I think this will just slow you down unnecessarily. somebody correct me below if I'm wrong?

Finally, the way you can get reads "any time" on the client is by: Always have an asynchronous read outstanding. That is, once the client connects to the server, immediately perform an async read to a given buffer that you know is "big enough" to hold whatever you might get. When your async read callback gets called (the one you provided to the async read method), you'll be told how much of the buffer got filled. Then, you can raise an event to the user of the client class (an event that you define), or you could call a callback, or you could do something. Right after you finish your event callback, go and perform ANOTHER asynchronous read. If there's nothing to read, that's okay, it will wait there for something to come in. Note that with an async read always pending, when the remote pipe is closed down, the async read will come back to you with "pipe closed" and "0 bytes read". This is normal.

here's a snippet of my read method, in my client class:

public void StartReadingAsync()
{
// Debug.WriteLine("Pipe " + FullPipeNameDebug() + " calling ReadAsync");
// okay we're connected, now immediately listen for incoming buffers
//
byte[] pBuffer = new byte[MaxLen];
m_pPipeStream.ReadAsync(pBuffer, 0, MaxLen).ContinueWith(t =>
{
// Debug.WriteLine("Pipe " + FullPipeNameDebug() + " finished a read request");
// before we call the user back, start reading ANOTHER buffer, so the network stack
// will have something to deliver into and we don't keep it waiting.
// We're called on the "anonymous task" thread. if we queue another call to
// the pipe's read, that request goes down into the kernel, onto a different thread
// and this will be called back again, later. it's not recursive, and perfectly legal.
int ReadLen = t.Result;
if (ReadLen == 0)
{
Debug.WriteLine("Got a null read length, remote pipe was closed");
if (PipeClosedEvent != null)
{
PipeClosedEvent(this, new EventArgs());
}
return;
}
// lodge ANOTHER read request BEFORE calling the user back. Doing this ensures
// the read is ready before we call the user back, which may cause a write request to happen,
// which will zip over to the other end of the pipe, cause a write to happen THERE, and we won't be ready to receive it
// (perhaps it will stay stuck in a kernel queue, and it's not necessary to do this)
//
StartReadingAsync();
if (PipeReadDataEvent != null)
{
PipeReadDataEvent(this, new PipeReadEventArgs(pBuffer, ReadLen));
}
else
{
Debug.Assert(false, "something happened");
}
});
}

Messages might get received out-of-order because StartReadingAsync is called before dispatching the payload. Might either complete synchronously, or async but there's no guarantee its event firing would not happen before ours. So should at least check for this, or make a payloads queue.
– hyperswSep 23 '16 at 19:13

Regarding Flush, per the docs: "The Flush method is not supported in the PipeStream class and does nothing when it is called."
– McGuireV10Jan 12 at 14:12

You are supposed to use following functions during asynchronous modes:

NamedPipeClientStream.BeginRead
NamedPipeClientStream.EndRead

and

NamedPipeServerStream.BeginWrite
NamedPipeServerStream.EndWrite

Also I am convinced proper implementation for WaitForPipeDrain() is always used before any writes to buffer because if you have previously written, you will need to check whether previous write to buffer has been read. If you write and then use WaitForPipeDrain() then subsequent call to your write function (even mistakenly) will overwrite first and then check. I haven't tried it but it can be logically thought to be so.