Esempio di tubi con nome


131

Come posso scrivere un semplice - minimo indispensabile per farlo funzionare - applicazione di test che illustra come usare IPC / Named Pipes?

Ad esempio, come si potrebbe scrivere un'applicazione console in cui il Programma 1 dice "Hello World" al Programma 2 e il Programma 2 riceve un messaggio e risponde "Roger That" al Programma 1.

Risposte:


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 Siamo spiacenti, è in .Net 4.5. Puoi usareThread.Sleep
— LB il

2
@Gusdor avrei potuto usare alcuni sync-primiteves. Ma sarebbe più difficile da leggere. Penso che basti dare un'idea su come usare NamedPipes
— LB

2
Se avete il problema che si chiude dopo un tubo lettura, controllare questa risposta: stackoverflow.com/a/895656/941764
— jgillich

11
Se stai utilizzando .NET 4.5, puoi sostituirlo Task.Factory.StartNewconTask.Run .
— Rudey,

2
Devi smaltire reader/ writer? In tal caso, ne elimini solo uno? Non ho mai visto un esempio in cui entrambi sono collegati allo stesso flusso.
— JoshVarty,

21

Per qualcuno che non conosce IPC e Named Pipes, ho trovato il seguente pacchetto NuGet di grande aiuto.

GitHub: Wrapper di tubi denominato per .NET 4.0

Per utilizzare prima installare il pacchetto:

PS> Install-Package NamedPipeWrapper

Quindi un server di esempio (copiato dal collegamento):

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

Esempio client:

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

client.Start();

La cosa migliore per me è che a differenza della risposta accettata qui supporta più client che parlano con un singolo server.


5
Non consiglierei questo pacchetto NuGet per la produzione. L'ho implementato e presenta alcuni bug, principalmente a causa della non essere in grado di sapere davvero quando un messaggio è stato completamente ricevuto nell'altra estremità della pipe (porta a connessioni interrotte o la connessione termina troppo presto (controlla il codice su github se non ti fidi di me, "WaitForPipeDrain" non viene chiamato quando dovrebbe), inoltre avrai più client anche quando solo uno è in ascolto perché ... troppi problemi). È triste perché è stato davvero facile da usare. Ho dovuto ricostruirne uno da zero con meno opzioni.
— Micaël Félix,

Sì, il punto è positivo, sfortunatamente quel manutentore originale non aggiorna il progetto da anni, fortunatamente, sebbene esistano numerose forcelle che risolvono i problemi discussi.
— Martin Laukkanen,

2
@MartinLaukkanen: Ciao, ho intenzione di usare NamedPipeWrapper, sai quale fork sta risolvendo questo bug? grazie
— Whiletrue,

17

Puoi effettivamente scrivere su una named pipe usando il suo nome, tra l'altro.

Aprire una shell dei comandi come amministratore per aggirare l'errore predefinito "Accesso negato":

echo Hello > \\.\pipe\PipeName

3

FYI dotnet core su linux non supporta namedpipes, prova invece tcplistener se sei su linux

Questo codice ha un client round trip un byte.

  • Il client scrive byte
  • Il server legge byte
  • Il server scrive byte
  • Il client legge byte

Console Server DotNet Core 2.0

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

Console client DotNet Core 2.0

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

L'uso di pipe nominate in questo modo per 2 processi mi rendeSystem Unauthorized Accesss Exception - path is denied
— Bercovici Adrian il

Non sei sicuro di correre come amministratore?
— patrick
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.