C# - Realizando a comunicação com Pipes - II


Hoje vamos tratar da comunicação entre processos usando Pipes (ou canais em uma tradução literal) na implementação feita na plataforma .NET.

Continuando o artigo anterior veremo agora como criar pipes anônimos.

Vamos fazer algo parecido com o exemplo do artigo anterior usando agora os pipes anônimos. Lembrando que os pipes anônimos são unidirecionais e só podem se comunicar com um cliente.

Dessa forma com pipes anônimos, duas Tasks(tarefas) serão criadas para se comunicar uma com a outra. Para sinalizar a criação do pipe, vamos usar um objeto ManualResetEventSlim.

A classe ManualResestEventSlim representa um evento de sincronização de thread que, quando sinalizado, deve ser redefinido manualmente.

No método Run da classe Program, duas tarefas são criadas que invocam os métodos Reader e Writer.

Vamos criar um vou criar um projeto Console  App (.NET Core) usando o VS 2017 Community com o nome NetCore_PipesAnonimos;

1- Criando o Pipe anônimo com o métodos de leitura e escrita

A seguir inclua no arquivo Program o código abaixo:

using System;
using System.IO;
using System.IO.Pipes;
using System.Threading;
using System.Threading.Tasks;
namespace AnonymousPipes
{
    public class Program
    {
        private string _pipeHandle;
        private ManualResetEventSlim _pipeHandleSet;
        public static void Main()
        {
            var p = new Program();
            p.Run();
            Console.ReadLine();
        }
        public void Run()
        {
            _pipeHandleSet = new ManualResetEventSlim(initialState: false);
            Task.Run(() => Reader());
            Task.Run(() => Writer());
        }
        private void Writer()
        {
            Console.WriteLine("pipe anônimo - writer");
            _pipeHandleSet.Wait();
            var pipeWriter = new AnonymousPipeClientStream(PipeDirection.Out, _pipeHandle);
            using (var writer = new StreamWriter(pipeWriter))
            {
                writer.AutoFlush = true;
                Console.WriteLine("iniciando o writer");
                for (int i = 0; i < 5; i++)
                {
                    writer.WriteLine($"Mensagem {i}");
                    Task.Delay(500).Wait();
                }
                writer.WriteLine("fim");
            }
        }
        private void Reader()
        {
            try
            {
                Console.WriteLine("pipe anônimo - reader");
                var pipeReader = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.None);
                using (var reader = new StreamReader(pipeReader))
                {
                    _pipeHandle = pipeReader.GetClientHandleAsString();
                    Console.WriteLine($"pipe handle: {_pipeHandle}");
                    _pipeHandleSet.Set();
                    bool fim = false;
                    while (!fim)
                    {
                        string line = reader.ReadLine();
                        Console.WriteLine(line);
                        if (line == "fim") fim = true;
                    }
                    Console.WriteLine("concluindo a leitura...");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

Vamos entender o código...

No método Main() criamos uma instância da classe e invocamos o método Run() que por sua vez cria duas threads com os métodos Writer e Reader.

O lado do servidor atua como um leitor criando um AnonymousPipeServerStream e definindo o PipeDirection.In.

O outro lado da comunicação precisa saber sobre o identificador do pipe do cliente tubo. Esse identificador é convertido em uma string do método GetClientHandleAsString e atribuído à variável _pipeHandle. Essa variável será usada posteriormente pelo cliente que atua como escritor.

Depois de processo inicial, o servidor de pipe pode ser ativado como um stream porque é um stream.

O código do cliente aguarda até que a variável _pipeHandleSet seja sinalizada e, portanto, possa abrir o handle do pipe referenciado pela variável _pipeHandle. O processamento posterior continua com um StreamWriter.

Executando o programa iremos obter o seguinte resultado:

Pegue o código dos exemplos aqui :  NetCore_PipesAnonimos.zip

"Porque o reino de Deus não é comida nem bebida, mas justiça, e paz, e alegria no Espírito Santo."
Romanos 14:17

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Referências:


José Carlos Macoratti