Introduction
The following code shows how to implement a named pipe message server using the async and await keywords for local out-of-proc communication between applications.
Background
I wanted to create an application that showed how to use named pipes for out-of-proc communication between two .NET applications. While creating the application, I starting investigating asynchronous calling of the message send and receive methods - this lead to the inclusion of Async CTP library v3.0 (which can be found here). The Async library was not easy to install and this link was very helpful.
Using the Code
Warning!
You will need to set up the Async CTP v3 before running the code. You will also need to re-reference the AsyncCTPLibrary.dll - which by default is located within your My Documents folder.
The Send Message Method
The send message method uses the async
keyword in the method signature to enable asynchronous calling. Firstly, create the named pipe client (with the given name on the local server), then a stream writer to write to the pipe's stream. Then connect and write the message to the stream. The writing to the stream is done using the await
keyword.
public static async void SendMessageAsync(string pipeName, string message)
{
try
{
using (var pipe = new NamedPipeClientStream(LOCAL_SERVER, pipeName,
PipeDirection.Out, PipeOptions.Asynchronous))
using (var stream = new StreamWriter(pipe))
{
pipe.Connect(DEFAULT_TIME_OUT);
await stream.WriteAsync(message);
}
}
catch (Exception exception)
{
OnSendMessageException(pipeName, new MessengerExceptionEventArgs(exception));
}
}
The Listening Method
The listening method also uses the async
keyword in the method signature to enable asynchronous calling. Firstly, create the named pipe server (with the given name), then wait for a connection - this is done asynchronously using the await
keyword. Once a connection is made, create a stream reader on the pipe, and read from the stream - again asynchronously using the await
keyword. Once the message is received, then invoke the action (called messageRecieved
), and disconnect the pipe. The whole process is wrapped in a while(true)
loop so that new messages can be continually received.
public static async void StartListeningAsync(string pipeName, Action<string> messageRecieved)
{
try
{
while (true)
{
using (var pipe = new NamedPipeServerStream(pipeName,
PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
{
await pipe.WaitForConnectionAsync();
using (var streamReader = new StreamReader(pipe))
{
var message = await streamReader.ReadToEndAsync();
if (messageRecieved != null)
{
messageRecieved(message);
}
}
if (pipe.IsConnected)
{
pipe.Disconnect();
}
}
}
}
catch (Exception exception)
{
OnSendMessageException(pipeName, new MessengerExceptionEventArgs(exception));
}
}
Usage
To use the message server, call the message server static
method, SendMessageAsync
using the TaskEx.Run
method - this will invoke the send
message on a separate thread, allowing the UI to continue to run uninterrupted.
TaskEx.Run(() => MessageServer.SendMessageAsync(pipeName, message));
To listen for messages, call the message server static
method, StartListeningAsync
using the TaskEx.Run
method - this will invoke the listening on a separate thread. When a message is received, the action parameter (messageReceived
) will be called. In this case, we want to show a message box back on the UI thread so we must Invoke a new Action on the Forms UI thread.
TaskEx.Run(() => MessageServer.StartListeningAsync(pipeName, messageReceievd =>
{
Invoke((Action)(() =>
{
var message = String.Format("Original Message:=\n\n{0}\nServer
details:=\n\nSending to pipe:={1}\nListening on pipe:={2}",
messageReceievd,
txtSendPipeName.Text,
txtListenPipeName.Text);
MessageBox.Show(this, message, "Message Received");
}));
}));
How to Run and Test
To run, create two instances of the application (either by running the .exe twice or starting two instances from within Visual Studio - Debug -> Start new instance). Then enter in App 1 the "Send Pipe Name" as "ping" and the "Listening Pipe Name" as "pong". In App 2, enter "pong" and "ping".
Then click the start button on each application, then hit the test button to send messages between the two applications.
Points of Interest
The Async
CTP library is really cool and makes async coding a lot easier to write and to read, but most of all much more fun.
Name pipes are a simple and easy way to send messages between two applications on a desktop.