使用Reactive Extensions从{NamedPipeServerStream读取

时间:2016-07-13 13:49:51

标签: system.reactive namedpipeserverstream

我可以使用以下代码读取2个线程通过NamedPipeClientStreams发送的消息:

客户端:

private static async void DoLogging(string context)
{
    try
    {
        var pipeClient = new NamedPipeClientStream(".", PipeName, PipeDirection.InOut, PipeOptions.Asynchronous);

        for (var i = 0; i < 10; i++)
        {
            if (!pipeClient.IsConnected)
                pipeClient.Connect(1000);

            var buffer = Encoding.UTF8.GetBytes($"Context {context}: Message {i}");

            await pipeClient.WriteAsync(buffer, 0, buffer.Length);

            pipeClient.Flush();

            Thread.Sleep(100);  // For testing purposes
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

服务器:

private static void ListenForConnection()
{
    while (true)
    {
        var pipeServer = new NamedPipeServerStream(PipeName, PipeDirection.InOut,
            NamedPipeServerStream.MaxAllowedServerInstances,
            PipeTransmissionMode.Message, PipeOptions.Asynchronous);

        var namedPipeListener = pipeServer.WaitForConnectionAsync(CancellationToken.None).ToObservable();

        namedPipeListener.SubscribeOn(Scheduler.Default).Subscribe(unit =>
        {
            HandleClient(pipeServer);
        });
    }
}

private static void HandleClient(PipeStream pipeServer)
{
    var bytes = new byte[BufferSize];
    var sb = new StringBuilder();

    while (true)
    {
        int numBytes;
        do
        {
            numBytes = pipeServer.Read(bytes, 0, BufferSize);
            if (numBytes > 0)
            {
                sb.Append(Encoding.UTF8.GetString(bytes, 0, numBytes));
            }
        } while (numBytes > 0 && !pipeServer.IsMessageComplete);

        var text = sb.ToString();

        if (!string.IsNullOrWhiteSpace(text))
        {
            Console.WriteLine(text.Trim());
            sb.Clear();
        }
    }
}

以上称为:

private const string PipeName = "SvTest.Pipe.Name";
private const int BufferSize = 1024;

private static void Main()
{
    try
    {
        var tasks = new Task[3];

        tasks[0] = Task.Run(() => ListenForConnection());
        tasks[1] = Task.Run(() => DoLogging("Thread 1"));
        tasks[2] = Task.Run(() => DoLogging("Thread 2"));

        Task.WaitAll(tasks);
    }
    catch (Exception ex)
    {
        LogException(ex);
    }

    Console.ReadLine();
}

如果我尝试使用RX读取流,我可以读取第一条消息,然后我得到一个&#34;管道坏了&#34; HandleClient方法如下所示的客户端线程中的错误:

private static void HandleClient(Stream pipeStream)
{
    var buffer = new byte[pipeStream.Length];
    var sb = new StringBuilder();

    var readObservable = pipeStream.ReadAsync(buffer, 0, buffer.Length).ToObservable();

    readObservable.SubscribeOn(Scheduler.Default).Subscribe(
        unit =>
        {
            Read(buffer, sb);
        },
        OnError,
        () => { ReadCompleted(sb); }, CancellationToken.None);
}

我假设服务器流在读取后关闭。我不确定如何保持流打开并从中读取。我能够找到的代码示例和文档使用旧的APM技术。我想使用.Net 4.6和RX库提供的最新/推荐技术。在我的应用程序中,客户端将在很长一段时间内随意发送消息。所以我希望管道保持每个客户端打开,以免每条消息产生连接开销。

我也很感谢关于边缘情况的任何指导,以便我最终得到坚如磐石的解决方案。

0 个答案:

没有答案