Click here to Skip to main content
Click here to Skip to main content

C# Named Pipes with Async

By , 16 Aug 2012
 

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 at http://www.microsoft.com/en-au/download/details.aspx?id=9983). The Async library was not easy to install and this were very helpful - http://blogs.msdn.com/b/lucian/archive/2011/11/01/async-ctp-v3-installation.aspx

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 you 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);

            // write the message to the pipe stream 
            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))
            {
                // wait for the connection
                await pipe.WaitForConnectionAsync();

                using (var streamReader = new StreamReader(pipe))
                {
                    // read the message from the stream - async
                    var message = await streamReader.ReadToEndAsync();
                    if (messageRecieved != null)
                    {
                        // invoke the message received action 
                        messageRecieved(message);
                    }
                }

                if (pipe.IsConnected)
                {
                    // must disconnect 
                    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 Receieved");
    }));
}));  

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". 

The 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. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Maddog Mike B
Software Developer (Senior)
Australia Australia
Member
http://maddogmikeb.blogspot.com.au/

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionSlow?memberMarcel Monteny8 Nov '12 - 11:37 
Thanks for the great example.
 
Is it normal that it takes 6 to 7 secondes to receive the sended message (on Windows 7)? Sleepy | :zzz:
Is there a faster way to communicate?
AnswerRe: Slow?memberMaddog Mike B8 Nov '12 - 12:58 
Hi Marcel,
 
This first time may be a little slow, but it should be faster after that. I've tested it on win 7 and didn't get responses that slow, do you have any 3rd party software running that may be intercepting the messages?
 
http://msdn.microsoft.com/en-us/library/aa178138(v=sql.80).aspx [^] says that they should be as fast as tcpip on a LAN or locally.
 
You could try chaning the constant
 
public const string LOCAL_SERVER = ".";
 
To your pc's name but "." Is usually faster and recommended.
 
Do you know which line it is stalling on?
 
Cheers,
 
Mike
GeneralRe: Slow?memberMarcel Monteny9 Nov '12 - 9:30 
Hi Mike,
 
Found the "Problem":
 
There is a debug pause at line 55 and 96:
#if DEBUG
System.Threading.Thread.Sleep(5000);
#endif
 
This was causing the delay.
 
Thans again
Marcel
QuestionDoesn't work in NET 4.5memberNemo19668 Nov '12 - 10:14 
This code doest work in .Net 4.5
 
pipe.WaitForConnectionAsync(); Doesn't exist in 4.5
AnswerRe: Doesn't work in NET 4.5memberMaddog Mike B8 Nov '12 - 12:50 
Sorry Nemo,
 
I had only tested this with .Net 3.5, but you could create your own extension method that mimics this function. Very annoying that they removed it in 4.5.
 
I'll try and get some time this weekend to try this out and update the article or reply to your comment with the results.
 
Thanks for letting me know.
 
Cheers,
 
Mike
GeneralRe: Doesn't work in NET 4.5memberNemo19669 Nov '12 - 6:55 
Thanks - good article though. Typical of MS to change the goalposts
 
thanks again
Nemo
GeneralRe: Doesn't work in NET 4.5 [modified]memberNemo19669 Nov '12 - 11:11 
I found a way in .Net 4.5 without the need for extra libraries
 
Please see my code at http://www.codeproject.com/Tips/492231/Csharp-Async-Named-Pipes
 
Regards
Nemo1966

modified 11 Nov '12 - 12:30.

GeneralMy vote of 5memberDnx_71 Nov '12 - 14:03 
Nice post and easy to understand

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 17 Aug 2012
Article Copyright 2012 by Maddog Mike B
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid