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.