Example of Named Pipes
Asked Answered
K

4

156

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.

Kaffir answered 10/12, 2012 at 17:37 Comment(0)
S
200
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();
                }
            });
        }
    }
}
Swaggering answered 10/12, 2012 at 18:16 Comment(8)
Just wondering what Line: 16 is supposed to be because there's no definition for 'Delay' in System.Thread.TasksKaffir
@JordanTrainor Sorry, it is in .Net 4.5. You can use Thread.SleepSwaggering
The use of Task in this example is pretty dire. It is verbose syntax and due to scheduling may not being even close to 1000ms.Xerarch
@Xerarch I could have used some sync-primiteves. But It would be more hard to read. I think it is enough to give an idea about how to use NamedPipesSwaggering
If you have the problem that the pipe closes after one read, check this answer: https://mcmap.net/q/146175/-system-io-exception-pipe-is-brokenDerma
Thanks a bunch mate! P.s. the server should have (!reader.EndOfStream) instead of while(true).Bascule
If you're using .NET 4.5, you can replace Task.Factory.StartNew with Task.Run.Aboutship
Do you have to dispose of reader/writer? If so, do you only dispose of one of them? I've never seen an example where both are attached to the same stream.Douma
B
27

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.

Basildon answered 7/11, 2015 at 11:24 Comment(6)
I wouldn't recommend this NuGet package for production. I've implemented it and it has some bugs, mainly due to not being able to really know when a message has been fully received in the other end of the pipe (leads to broken connections, or connection ending too soon (check the code on github if you don't trust me, "WaitForPipeDrain" isn't called when it should), plus you'll have multiple clients even when only one is listening because... too many issues). It's sad because it was really easy to use. I had to rebuild one from scratch with less options.Hindu
Yes good point, unfortunately that original maintainer has not updated the project for years, fortunately though a number of forks exist most of which fix the issues you discussed.Basildon
@MartinLaukkanen : Hello, I plan to use NamedPipeWrapper, You you know which fork is fixing this bug ? thanksPerishing
@MartinLaukkanen Can we have the fork that fixed the bugs mentioned?Ayer
I don't recall which one I used specifically, but I would suggest reviewing the commits on the fork network graph to determine which one fixes the issues you are concerned with: github.com/acdvorak/named-pipe-wrapper/networkBasildon
I'd also avoid this package. There is a potential security issue because it uses BinaryFormatter. I refactored it heavily but by the end there was nothing much of the original left.Frida
S
24

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
Spectator answered 14/6, 2016 at 20:43 Comment(0)
A
5

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 <-- 
            });
        }
    }
}
Anna answered 14/3, 2018 at 15:32 Comment(2)
Using named pipes just like this for 2 processes renders me System Unauthorized Accesss Exception - path is denied Jeane
Not sure maybe run as admin?Anna

© 2022 - 2024 — McMap. All rights reserved.