0

I chose NamedPipes over TCP because I needed two applications on the same machine to talk to each other. I wanted exceedingly simple, quick, and easy, unfortunately it has proven to be the opposite.

Server sends two messages to client, client sends one message to the server. However, the client stalls on the second ReadLineAsync, despite two messages being there, and also the client stalls upon calling WriteLineAsync.

Here's my complete wrapper class used by both the client and server:

public class CNamedPipe : IDisposable
{
    private PipeStream _stream;
    private StreamReader _reader;
    private StreamWriter _writer;

    public void Host(string pipeName)
    {
        _stream = new NamedPipeServerStream(pipeName, PipeDirection.InOut);
        Task.Run(ServerWaitForConnectionsAync);
    }

    public void Connect(string pipeName, string serverName = ".")
    {
        _stream = new NamedPipeClientStream(serverName, pipeName, PipeDirection.InOut);
        Task.Run(ClientConnectAsync);
    }

    private async Task ServerWaitForConnectionsAync()
    {
        while (!IsClosed)
        {
            await Server.WaitForConnectionAsync();
            CreateReaderWriter();
            Console.WriteLine("New connection!");
        }

        Console.WriteLine("Stopped waiting for new connections.");
    }

    private async Task ClientConnectAsync()
    {
        await Client.ConnectAsync();
        CreateReaderWriter();
    }

    private void CreateReaderWriter()
    {
        _reader = new StreamReader(_stream);

        _writer = new StreamWriter(_stream);
        _writer.AutoFlush = true;

        Task.Run(ReadDataAsync);
        Task.Run(WriteDataAsync);
    }

    private NamedPipeServerStream Server
    {
        get
        {
            return _stream as NamedPipeServerStream;
        }
    }

    public NamedPipeClientStream Client
    {
        get
        {
            return _stream as NamedPipeClientStream;
        }
    }

    private ConcurrentQueue<string> _readQueue = new ConcurrentQueue<string>();

    private async Task ReadDataAsync()
    {
        while (!IsClosed && _stream.IsConnected)
        {
            string message = await _reader.ReadLineAsync();
            Console.WriteLine($"Received: {message}");
            _readQueue.Enqueue(message);
        }

        Console.WriteLine("ReadDataAsync completed.");
    }

    private ConcurrentQueue<string> _writeQueue = new ConcurrentQueue<string>();

    private async Task WriteDataAsync()
    {
        while (!IsClosed && _stream.IsConnected)
        {
            bool wroteAny = false;

            if (_writeQueue.TryDequeue(out string message))
            {
                try
                {
                    await _writer.WriteLineAsync(message);
                    await _writer.FlushAsync();
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Exception on write: {ex}");
                    throw;
                }
                wroteAny = true;
            }

            if (!wroteAny)
                await Task.Delay(100);
        }

        Console.WriteLine("WriteDataAsync completed.");
    }




    public IEnumerable<string> TryRead()
    {
        while (_readQueue.Count > 0)
        {
            if (_readQueue.TryDequeue(out string ret) && !string.IsNullOrEmpty(ret))
                yield return ret;
        }
    }

    public void Write(string message)
    {
        _writeQueue.Enqueue(message);
    }

    private bool _isClosed = false;

    public bool IsClosed
    {
        get
        {
            return _isClosed || _stream == null;
        }
    }

    public bool IsConnected
    {
        get
        {
            return !IsClosed && _stream.IsConnected;
        }
    }

    public void Close()
    {
        _isClosed = true;
        if (_stream != null)
        {
            _stream.Close();
        }
    }

    public void Dispose()
    {
        Close();

        if (_stream != null)
        {
            _stream.Dispose();
            _stream = null;
        }
    }
}

They both say they're connected. EDIT, after some fiddling, manually try/catching and printing errors to the console, it does appear that calling FlushAsync triggers a "Pipe is broken" exception. I appreciate your assistance.

0