Contoh Pipa Bernama

131

Bagaimana cara menulis minimum - sederhana yang diperlukan agar dapat berfungsi - aplikasi uji yang menggambarkan cara menggunakan IPC / Named Pipes?

Misalnya, bagaimana seseorang akan menulis aplikasi konsol di mana Program 1 mengatakan "Hello World" ke Program 2 dan Program 2 menerima pesan dan membalas "Roger That" ke Program 1.

Pelatih Jordan
sumber

Jawaban:

166
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();
                }
            });
        }
    }
}
LB
sumber
1
@JordanTrainor Maaf, ada di .Net 4.5. Anda dapat menggunakanThread.Sleep
LB
2
@ Goddor saya bisa menggunakan beberapa sync-primiteves. Tetapi akan lebih sulit untuk dibaca. Saya pikir itu sudah cukup untuk memberikan ide tentang cara menggunakan NamedPipes
LB
2
Jika Anda memiliki masalah bahwa pipa ditutup setelah dibaca, periksa jawaban ini: stackoverflow.com/a/895656/941764
jgillich
11
Jika Anda menggunakan .NET 4.5, Anda bisa menggantinya Task.Factory.StartNewdenganTask.Run .
Rudey
2
Apakah Anda harus membuang reader/ writer? Jika demikian, apakah Anda hanya membuang salah satunya? Saya belum pernah melihat contoh di mana keduanya terhubung ke aliran yang sama.
JoshVarty
21

Untuk seseorang yang baru mengenal IPC dan Named Pipes, saya menemukan paket NuGet berikut ini sangat membantu.

GitHub: Named Pipe Wrapper untuk .NET 4.0

Untuk menggunakan, instal dulu paket:

PS> Install-Package NamedPipeWrapper

Kemudian server contoh (disalin dari tautan):

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

Contoh klien:

var client = new NamedPipeClient<SomeClass>("MyServerPipe");
client.ServerMessage += delegate(NamedPipeConnection<SomeClass> conn, SomeClass message)
    {
        Console.WriteLine("Server says: {0}", message.Text);
    };

client.Start();

Hal terbaik untuk saya bagi saya adalah tidak seperti jawaban yang diterima di sini, ia mendukung banyak klien yang berbicara dengan satu server.

Martin Laukkanen
sumber
5
Saya tidak akan merekomendasikan paket NuGet ini untuk produksi. Saya telah mengimplementasikannya dan memiliki beberapa bug, terutama karena tidak dapat benar-benar tahu kapan pesan telah sepenuhnya diterima di ujung lain pipa (mengarah ke koneksi yang terputus, atau koneksi berakhir terlalu cepat (periksa kode pada github jika Anda tidak mempercayai saya, "WaitForPipeDrain" tidak dipanggil kapan seharusnya), plus Anda akan memiliki beberapa klien bahkan ketika hanya satu yang mendengarkan karena ... terlalu banyak masalah). Menyedihkan karena sangat mudah digunakan. Saya harus membangun satu dari awal dengan lebih sedikit opsi.
Micaël Félix
Ya poin bagus, sayangnya pemelihara asli tidak memperbarui proyek selama bertahun-tahun, untungnya meskipun ada sejumlah garpu yang sebagian besar memperbaiki masalah yang Anda diskusikan.
Martin Laukkanen
2
@ MartinLaukkanen: Halo, saya berencana menggunakan NamedPipeWrapper, Anda tahu garpu mana yang memperbaiki bug ini? terima kasih
Whiletrue
17

Anda benar-benar dapat menulis ke pipa bernama menggunakan namanya, btw.

Buka shell perintah sebagai Administrator untuk mengatasi kesalahan "Akses ditolak":

echo Hello > \\.\pipe\PipeName
Michael Blankenship
sumber
3

FYI dotnet core di linux tidak mendukung namedpipes, coba tcplistener sebagai gantinya jika Anda berada di linux

Kode ini memiliki klien round trip byte.

  • Klien menulis byte
  • Server membaca byte
  • Server menulis byte
  • Klien membaca 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 <-- 
            });
        }
    }
}
patrick
sumber
Menggunakan pipa bernama seperti ini untuk 2 proses menjadikan sayaSystem Unauthorized Accesss Exception - path is denied
Bercovici Adrian
Tidak yakin mungkin dijalankan sebagai admin?
patrick