Example of Named Pipes
How do I write a simple--bare minimum needed for it to work--test application that illustrates how to use IPC/Named Pipes?
For example, how would one write a console application where Program 1 says "Hello World" to Program 2 and Program 2 receives message and replies "Roger That" to Program 1.
using System;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
StartServer();
Task.Delay(1000).Wait();
//Client
var client = new NamedPipeClientStream("PipesOfPiece");
client.Connect();
StreamReader reader = new StreamReader(client);
StreamWriter writer = new StreamWriter(client);
while (true)
{
string input = Console.ReadLine();
if (String.IsNullOrEmpty(input)) break;
writer.WriteLine(input);
writer.Flush();
Console.WriteLine(reader.ReadLine());
}
}
static void StartServer()
{
Task.Factory.StartNew(() =>
{
var server = new NamedPipeServerStream("PipesOfPiece");
server.WaitForConnection();
StreamReader reader = new StreamReader(server);
StreamWriter writer = new StreamWriter(server);
while (true)
{
var line = reader.ReadLine();
writer.WriteLine(String.Join("", line.Reverse()));
writer.Flush();
}
});
}
}
}
For someone who is new to IPC and Named Pipes, I found the following NuGet package to be a great help.
GitHub: Named Pipe Wrapper for .NET 4.0
To use first install the package:
PS> Install-Package NamedPipeWrapper
Then an example server (copied from the link):
var server = new NamedPipeServer<SomeClass>("MyServerPipe");
server.ClientConnected += delegate(NamedPipeConnection<SomeClass> conn)
{
Console.WriteLine("Client {0} is now connected!", conn.Id);
conn.PushMessage(new SomeClass { Text: "Welcome!" });
};
server.ClientMessage += delegate(NamedPipeConnection<SomeClass> conn, SomeClass message)
{
Console.WriteLine("Client {0} says: {1}", conn.Id, message.Text);
};
server.Start();
Example client:
var client = new NamedPipeClient<SomeClass>("MyServerPipe");
client.ServerMessage += delegate(NamedPipeConnection<SomeClass> conn, SomeClass message)
{
Console.WriteLine("Server says: {0}", message.Text);
};
client.Start();
Best thing about it for me is that unlike the accepted answer here it supports multiple clients talking to a single server.
You can actually write to a named pipe using its name, btw.
Open a command shell as Administrator to get around the default "Access is denied" error:
echo Hello > \\.\pipe\PipeName
Linux dotnet core doesn't support namedpipes!
Try TcpListener if you deploy to Linux
This NamedPipe Client/Server code round trips a byte to a server.
- Client writes byte
- Server reads byte
- Server writes byte
- Client reads byte
DotNet Core 2.0 Server ConsoleApp
using System;
using System.IO.Pipes;
using System.Threading.Tasks;
namespace Server
{
class Program
{
static void Main(string[] args)
{
var server = new NamedPipeServerStream("A", PipeDirection.InOut);
server.WaitForConnection();
for (int i =0; i < 10000; i++)
{
var b = new byte[1];
server.Read(b, 0, 1);
Console.WriteLine("Read Byte:" + b[0]);
server.Write(b, 0, 1);
}
}
}
}
DotNet Core 2.0 Client ConsoleApp
using System;
using System.IO.Pipes;
using System.Threading.Tasks;
namespace Client
{
class Program
{
public static int threadcounter = 1;
public static NamedPipeClientStream client;
static void Main(string[] args)
{
client = new NamedPipeClientStream(".", "A", PipeDirection.InOut, PipeOptions.Asynchronous);
client.Connect();
var t1 = new System.Threading.Thread(StartSend);
var t2 = new System.Threading.Thread(StartSend);
t1.Start();
t2.Start();
}
public static void StartSend()
{
int thisThread = threadcounter;
threadcounter++;
StartReadingAsync(client);
for (int i = 0; i < 10000; i++)
{
var buf = new byte[1];
buf[0] = (byte)i;
client.WriteAsync(buf, 0, 1);
Console.WriteLine($@"Thread{thisThread} Wrote: {buf[0]}");
}
}
public static async Task StartReadingAsync(NamedPipeClientStream pipe)
{
var bufferLength = 1;
byte[] pBuffer = new byte[bufferLength];
await pipe.ReadAsync(pBuffer, 0, bufferLength).ContinueWith(async c =>
{
Console.WriteLine($@"read data {pBuffer[0]}");
await StartReadingAsync(pipe); // read the next data <--
});
}
}
}