c# - Ejemplo de canalizaciones con nombre
ipc named-pipes (4)
¿Cómo escribo un simple (mínimo indispensable para que funcione), una aplicación de prueba que ilustra cómo usar IPC / Named Pipes?
Por ejemplo, ¿cómo se podría escribir una aplicación de consola donde el Programa 1 dice "Hola mundo" al Programa 2 y el Programa 2 recibe un mensaje y responde "Entendido" al Programa 1.
En realidad, puede escribir en una tubería con nombre usando su nombre, por cierto.
Abra un shell de comando como administrador para evitar el error predeterminado "Acceso denegado":
echo Hello > //./pipe/PipeName
Este código tiene un cliente de ida y vuelta por byte.
- El cliente escribe el byte
- El servidor lee el byte
- El servidor escribe el byte
- El cliente lee el byte
Consola de servidor 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);
}
}
}
}
Consola de cliente DotNet Core 2.0 Client
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 <--
});
}
}
}
Para alguien que es nuevo en IPC y Named Pipes, encontré que el siguiente paquete NuGet es de gran ayuda.
GitHub: Envoltorio de tuberías con nombre para .NET 4.0
Para usar primero instala el paquete:
PS> Install-Package NamedPipeWrapper
Luego un servidor de ejemplo (copiado del enlace):
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();
Cliente de ejemplo:
var client = new NamedPipeClient<SomeClass>("MyServerPipe");
client.ServerMessage += delegate(NamedPipeConnection<SomeClass> conn, SomeClass message)
{
Console.WriteLine("Server says: {0}", message.Text);
};
client.Start();
Lo mejor de mí es que, a diferencia de la respuesta aceptada aquí, es compatible con múltiples clientes que hablan con un solo servidor.
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();
}
});
}
}
}