November 20th, 2008
Using Named Pipes in C# / Windows - 3
If you're new here, you may want to subscribe to my RSS feed. Thanks for visiting!

Communication between different threads in a process is trivial as they share the same objects in memory. But what if you would like to communicate with a different process (program) on the same computer? You could open a TCP/IP port to share data but the added overhead of this would slow down your program if you send a lot of data.
Traditionally you would use a pipe: a pseudo file that allows one process to write and another to process to read. This is very similar to reading and writing from a file. This is more efficient as the information is passed straight through the kernel between processes and avoids the network stack overhead.
There are two kinds of pipes:
Anonymous pipes
These are typically used for communication between a parent and child process. As the pipe does not have a name we need to be able to pass a handle to it from one process to another. Typically this is done by passing this handle as an argument when starting the child process.
Named pipes
Named pipes are more generally useful. If a process is aware of the name of a pipe it can connect to it. There is no need for an immediate parent / child relationship. As long as the parent process makes the pipe available, other processes can connect to it.
Pipes and Windows
The Windows OS offers a solid set of named and unnamed pipe function calls in the kernel. But for some reason Microsoft didn’t actually include pipes in C# until .NET 3.5. The support for pipes is now included in the System.IO.Pipes class. In the intervening years enterprising programmers created their own set of non-portable bindings to the Kernel32 calls and on Linux the Mono teambuild their own set of calls to support Unix sockets in the Mono.Unix.UnixPipes class.
As a result there is currently no portable way to implement pipes under both .NET/Windows and Linux/Mono. In the following example I show you how to create a named pipe for Windows.
Because of the nature of a named pipe — we are going to need two programs: one that establishes the pipe, and another one that reads from the pipe.
Example: Named Pipes in Visual C# / .NET 3.5
With the introduction of System.IO.Pipes in .NET 3.5 creating and connecting to a pipe has become very straightforward.
- NamedPipeServerStream creates a pipe
- NamedPipeClientStream connects to an existing pipe
In the below example we simulate the communication between two processes by creating two threads instead. This makes debugging this example easier but in reality this could also have been an example of communication between two separate processes on the same computer.
We also make implicity use of the fact that NamedPipeClientStream.Connect() will wait for the pipe to be created if it can’t find it on its first try. If this is not acceptable it is also possible to call Connect with a time-out in milliseconds — if the pipe is not created in the time specified the function will fail.
using System;
using System.IO;
using System.IO.Pipes;
using System.Threading;
namespace PipeApplication1
{
class ProgramPipeTest
{
public void ThreadStartServer()
{
// Create a name pipe
using (NamedPipeServerStream pipeStream = new NamedPipeServerStream("mytestpipe"))
{
Console.WriteLine("[Server] Pipe created {0}", pipeStream.GetHashCode());
// Wait for a connection
pipeStream.WaitForConnection();
Console.WriteLine("[Server] Pipe connection established");
using (StreamReader sr = new StreamReader(pipeStream))
{
string temp;
// We read a line from the pipe and print it together with the current time
while ((temp = sr.ReadLine()) != null)
{
Console.WriteLine("{0}: {1}", DateTime.Now, temp);
}
}
}
Console.WriteLine("Connection lost");
}
public void ThreadStartClient(object obj)
{
// Ensure that we only start the client after the server has created the pipe
ManualResetEvent SyncClientServer = (ManualResetEvent)obj;
// Only continue after the server was created -- otherwise we just fail badly
// SyncClientServer.WaitOne();
using (NamedPipeClientStream pipeStream = new NamedPipeClientStream("mytestpipe"))
{
// The connect function will indefinately wait for the pipe to become available
// If that is not acceptable specify a maximum waiting time (in ms)
pipeStream.Connect();
Console.WriteLine("[Client] Pipe connection established");
using (StreamWriter sw = new StreamWriter(pipeStream))
{
sw.AutoFlush = true;
string temp;
Console.WriteLine("Please type a message and press [Enter], or type 'quit' to exit the program");
while ((temp = Console.ReadLine()) != null)
{
if (temp == "quit") break;
sw.WriteLine(temp);
}
}
}
}
static void Main(string[] args)
{
// To simplify debugging we are going to create just one process, and have two tasks
// talk to each other. (Which is a bit like me sending an e-mail to my co-workers)
ProgramPipeTest Server = new ProgramPipeTest();
ProgramPipeTest Client = new ProgramPipeTest();
Thread ServerThread = new Thread( Server.ThreadStartServer );
Thread ClientThread = new Thread(Client.ThreadStartClient);
ServerThread.Start();
ClientThread.Start();
}
}
}
Image credit: TanakaWho
Tags: Learn C#, named pipes, windows









Except where otherwise noted, content on this site is
September 7th, 2009 at 10:16 pm
A big THANK YOU for your example, which showed me a way to get rid of a hanging-up problem, probably caused by using the Peak() method. The solution simply was not to use it
June 3rd, 2010 at 2:41 am
Thank you very much. Nice, clear and simple. Those named pipes are damn fast too !
January 5th, 2011 at 2:58 am
Thank you for this great! sample. Really appreciate it!