duplex operation between two processes using named pipes in c#

jambodev picture jambodev · Feb 12, 2013 · Viewed 8.4k times · Source

I am trying to use named pipes to communicate between a server and a client process on the same machine. server sends a message to client, client does something with it and returns a result, and server is supposed to get the result.

here is the code for server:

using System;
using System.IO;
using System.IO.Pipes;

class PipeServer
{
    static void Main()
    {
        using (NamedPipeServerStream pipeServer =
            new NamedPipeServerStream("testpipe", PipeDirection.InOut))
        {
            Console.WriteLine("NamedPipeServerStream object created.");

            // Wait for a client to connect
            Console.Write("Waiting for client connection...");
            pipeServer.WaitForConnection();

            Console.WriteLine("Client connected.");
            try
            {
                // Read user input and send that to the client process.
                using (StreamWriter sw = new StreamWriter(pipeServer))
                {
                    sw.AutoFlush = true;
                    Console.Write("Enter text: ");
                    sw.WriteLine(Console.ReadLine());
                }

                pipeServer.WaitForPipeDrain();

                using (StreamReader sr = new StreamReader(pipeServer))
                {
                    // Display the read text to the console 
                    string temp;

                    // Wait for result from the client. 
                    while ((temp = sr.ReadLine()) != null)
                    {
                        Console.WriteLine("[CLIENT] Echo: " + temp);
                    }
                }

            }
            // Catch the IOException that is raised if the pipe is 
            // broken or disconnected.
            catch (IOException e)
            {
                Console.WriteLine("ERROR: {0}", e.Message);
            }
        }
    }
}

and here is the code for client:

using System;
using System.IO;
using System.IO.Pipes;

class PipeClient
{
    static void Main(string[] args)
    {
        using (NamedPipeClientStream pipeClient =
            new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut))
        {

            // Connect to the pipe or wait until the pipe is available.
            Console.Write("Attempting to connect to pipe...");
            pipeClient.Connect();

            Console.WriteLine("Connected to pipe.");
            Console.WriteLine("There are currently {0} pipe server instances open.",
               pipeClient.NumberOfServerInstances);
            using (StreamReader sr = new StreamReader(pipeClient))
            {
                // Display the read text to the console
                string temp;
                while ((temp = sr.ReadLine()) != null)
                {
                    Console.WriteLine("Received from server: {0}", temp);
                }
            }


            // send the "result" back to the Parent process.
            using (StreamWriter sw = new StreamWriter(pipeClient))
            {
                sw.AutoFlush = true;
                sw.WriteLine("Result");
            }

            pipeClient.WaitForPipeDrain();

        }
        Console.Write("Press Enter to continue...");
        Console.ReadLine();
    }
}

But in the server code, on line pipeServer.WaitForPipeDrain(); I get an ObjectDisposedException and it says "cannot access a closed pipe."

I also get the same error in the client code on when setting sw.AutoFlush to true.

Basically I couldn't find an example of duplex named pipe in c#. I either need that, or an example of anonynous pipe, with two pipes one for reading and one for writting between a parent and a child process.

Thanks in Advance.

Answer

TGlatzer picture TGlatzer · Feb 12, 2013

The Problem is the using block of the StreamWriter, which will close the underlying Stream (which is your pipe here). If you don't use that block it should work.

You could do the following:

using (var pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.InOut))
using (var streamReader = new StreamReader(pipeServer))
using (var streamWriter = new StreamWriter(pipeServer))
{
   // ... Your code ..
}

As Johannes Egger pointed out, the StreamWriter flushes the stream on Dispose(), so the StreamWriter should be disposed first and thus be the inner-most object to dispose.