İsimli Borular Örneği


131

IPC / Named Pipes'ın nasıl kullanılacağını gösteren basit - en azından çalışması için gerekli - test uygulamasını nasıl yazabilirim?

Örneğin, Program 1'in Program 2'ye "Merhaba Dünya" dediği ve Program 2'nin mesajı aldığı ve Program 1'e "Anlaşıldı" yanıtını verdiği bir konsol uygulaması nasıl yazılır?

Yanıtlar:


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

1
@JordanTrainor Üzgünüm, .Net 4.5 içinde. KullanabilirsinizThread.Sleep
LB

2
@Gusdor Bazı sync-primiteves'leri kullanabilirdim. Ama okumak daha zor olurdu. NamedPipes'ın nasıl kullanılacağına dair bir fikir vermenin yeterli olduğunu düşünüyorum
LB

2
Bir okumadan sonra borunun kapanmasıyla ilgili sorun yaşıyorsanız, şu yanıtı kontrol edin: stackoverflow.com/a/895656/941764
jgillich

11
.NET 4.5 kullanıyorsanız, şunları yapabilirsiniz değiştirmek Task.Factory.StartNewileTask.Run .
Rudey

2
reader/ İmha etmeniz gerekiyor writermu? Öyleyse, bunlardan yalnızca birini mi atıyorsunuz? Her ikisinin de aynı akışa eklendiği bir örnek görmedim.
JoshVarty

21

IPC ve Named Pipes konusunda yeni olan biri için aşağıdaki NuGet paketini harika bir yardımcı buldum.

GitHub: .NET 4.0 için Adlandırılmış Boru Sarmalayıcı

İlk önce paketi kullanmak için:

PS> Install-Package NamedPipeWrapper

Ardından örnek bir sunucu (bağlantıdan kopyalanır):

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

Örnek müşteri:

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

client.Start();

Benim için en iyi yanı, burada kabul edilen cevabın aksine, birden çok istemcinin tek bir sunucuyla konuşmasını desteklemesi.


5
Bu NuGet paketini üretim için önermem. Bunu uyguladım ve bazı hatalar var, esas olarak borunun diğer ucunda bir mesajın ne zaman tam olarak alındığını gerçekten bilememekten dolayı (kopuk bağlantılara yol açar veya bağlantının çok erken bitmesine neden olur (kodu kontrol edin) github bana güvenmiyorsanız, "WaitForPipeDrain" gerektiği zaman çağrılmaz), ayrıca birden fazla müşteriniz olur, çünkü tek bir kişi dinlerken bile çok fazla sorun var). Üzücü çünkü kullanımı gerçekten çok kolaydı. Daha az seçenekle sıfırdan yeniden inşa etmek zorunda kaldım.
Micaël Félix

Evet, iyi bir nokta, ne yazık ki orijinal bakımcı projeyi yıllardır güncellemedi, neyse ki, çoğu tartıştığınız sorunları gideren birkaç çatal var.
Martin Laukkanen

2
@MartinLaukkanen: Merhaba, NamedPipeWrapper'ı kullanmayı planlıyorum, bu hatayı hangi çatalın düzelttiğini biliyor musunuz? teşekkürler
Whiletrue

17

Aslında adlandırılmış bir boruya onun adını (btw) kullanarak yazabilirsiniz.

Varsayılan "Erişim reddedildi" hatasını aşmak için Yönetici olarak bir komut kabuğu açın:

echo Hello > \\.\pipe\PipeName

3

Bilginize Linux'taki dotnet çekirdeği adlandırılmış boruları desteklemiyor, linux'taysanız bunun yerine tcplistener'ı deneyin

Bu kodda bir müşteri gidiş dönüş baytı bulunur.

  • İstemci bayt yazar
  • Sunucu bayt okur
  • Sunucu bayt yazar
  • İstemci bayt okur

DotNet Core 2.0 Sunucu 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 İstemci Konsolu

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

Adlandırılmış boruları 2 işlem için bu şekilde kullanmak beni System Unauthorized Accesss Exception - path is denied
yaratıyor

Yönetici olarak çalıştırılabileceğinden emin değil misiniz?
patrick
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.