C# 异步使用NamedPipeServerStream和NamedPipeClientStream

C# 异步使用NamedPipeServerStream和NamedPipeClientStream,c#,.net,named-pipes,C#,.net,Named Pipes,我对服务器/客户端体系结构有以下要求: 编写一个异步工作的服务器/客户机 通信需要是双工的,即两端读写 多个客户端可以在任何给定时间连接到服务器 服务器/客户机应等待它们可用,并最终建立连接 一旦客户端连接,它就应该写入流 然后服务器应该从流中读取响应并将响应写回客户端 最后,客户端应该读取响应,通信应该结束 因此,考虑到以下要求,我编写了以下代码,但我不太确定,因为管道文档有点缺乏,不幸的是,代码似乎无法正常工作,它挂起在某个点上 namespace PipesAsyncAwait471 {

我对服务器/客户端体系结构有以下要求:

  • 编写一个异步工作的服务器/客户机

  • 通信需要是双工的,即两端读写

  • 多个客户端可以在任何给定时间连接到服务器

  • 服务器/客户机应等待它们可用,并最终建立连接

  • 一旦客户端连接,它就应该写入流

  • 然后服务器应该从流中读取响应并将响应写回客户端

  • 最后,客户端应该读取响应,通信应该结束

  • 因此,考虑到以下要求,我编写了以下代码,但我不太确定,因为管道文档有点缺乏,不幸的是,代码似乎无法正常工作,它挂起在某个点上

    namespace PipesAsyncAwait471
    {
        using System;
        using System.Collections.Generic;
        using System.IO.Pipes;
        using System.Linq;
        using System.Threading.Tasks;
    
        internal class Program
        {
            private static async Task Main()
            {
                List<Task> tasks = new List<Task> {
                    HandleRequestAsync(),
                };
    
                tasks.AddRange(Enumerable.Range(0, 10).Select(i => SendRequestAsync(i, 0, 5)));
    
                await Task.WhenAll(tasks);
            }
    
            private static async Task HandleRequestAsync()
            {
                using (NamedPipeServerStream server = new NamedPipeServerStream("MyPipe",
                                                                                PipeDirection.InOut,
                                                                                NamedPipeServerStream.MaxAllowedServerInstances,
                                                                                PipeTransmissionMode.Message,
                                                                                PipeOptions.Asynchronous))
                {
                    Console.WriteLine("Waiting...");
    
                    await server.WaitForConnectionAsync().ConfigureAwait(false);
    
                    if (server.IsConnected)
                    {
                        Console.WriteLine("Connected");
    
                        if (server.CanRead) {
                            // Read something...
                        }
    
                        if (server.CanWrite) {
                            // Write something... 
    
                            await server.FlushAsync().ConfigureAwait(false);
    
                            server.WaitForPipeDrain();
                        }
    
                        server.Disconnect();
    
                        await HandleRequestAsync().ConfigureAwait(false);
                    }
                }
            }
    
            private static async Task SendRequestAsync(int index, int counter, int max)
            {
                using (NamedPipeClientStream client = new NamedPipeClientStream(".", "MyPipe", PipeDirection.InOut, PipeOptions.Asynchronous))
                {
                    await client.ConnectAsync().ConfigureAwait(false);
    
                    if (client.IsConnected)
                    {
                        Console.WriteLine($"Index: {index} Counter: {counter}");
    
                        if (client.CanWrite) {
                            // Write something...
    
                            await client.FlushAsync().ConfigureAwait(false);
    
                            client.WaitForPipeDrain();
                        }
    
                        if (client.CanRead) {
                            // Read something...
                        }
                    }
    
                    if (counter <= max) {
                        await SendRequestAsync(index, ++counter, max).ConfigureAwait(false);
                    }
                    else {
                        Console.WriteLine($"{index} Done!");
                    }
                }
            }
        }
    }
    
    namespace PipesAsyncAwait471
    {
    使用制度;
    使用System.Collections.Generic;
    使用System.IO.Pipes;
    使用System.Linq;
    使用System.Threading.Tasks;
    内部课程计划
    {
    专用静态异步任务Main()
    {
    列表任务=新列表{
    HandleRequestAsync(),
    };
    tasks.AddRange(Enumerable.Range(0,10).Select(i=>SendRequestAsync(i,0,5));
    等待任务。何时(任务);
    }
    专用静态异步任务HandleRequestAsync()
    {
    使用(NamedPipeServerStream server=newnamedpipeserverstream(“MyPipe”,
    PipeDirection.InOut,
    NamedPipeServerStream.MaxAllowedServerInstances,
    PipeTransmissionMode.Message,
    PipeOptions.Asynchronous)
    {
    控制台。WriteLine(“等待…”);
    wait server.WaitForConnectionAsync().ConfigureWait(false);
    如果(服务器已断开连接)
    {
    控制台。写入线(“连接”);
    if(server.CanRead){
    //读点什么。。。
    }
    if(server.CanWrite){
    //写点什么。。。
    wait server.FlushAsync().configurewait(false);
    WaitForPipeDrain();
    }
    server.Disconnect();
    await HandlerRequestAsync().ConfigureAwait(false);
    }
    }
    }
    专用静态异步任务SendRequestAsync(int索引、int计数器、int最大值)
    {
    使用(NamedPipeClientStream客户端=新的NamedPipeClientStream(“.”,“MyPipe”,PipeDirection.InOut,PipeOptions.Asynchronous))
    {
    wait client.ConnectAsync().configurewait(false);
    如果(客户端已断开连接)
    {
    WriteLine($“索引:{Index}计数器:{Counter}”);
    if(client.CanWrite){
    //写点什么。。。
    wait client.FlushAsync().configurewait(false);
    client.WaitForPipeDrain();
    }
    if(client.CanRead){
    //读点什么。。。
    }
    }
    
    如果(计数器在断开连接时,
    WaitForPipeDrain()
    会由于管道破裂而引发
    IOException

    如果在服务器
    任务中发生这种情况,则它将永远不会侦听下一个连接,并且所有剩余的客户端连接都将挂起
    ConnectAsync()

    如果这发生在一个客户端任务中,那么它将不会继续递归并增加该索引的计数器

    如果将对
    WaitForPipeDrain()
    的调用包装在
    try
    /
    catch
    中,程序将永远继续运行,因为函数
    HandleRequestAsync()
    是无限递归的

    简言之,要使其发挥作用:

  • WaitForPipeDrain()处理
    IOException
  • HandleRequestAsync()
    必须在某个时候完成

  • 以下是经过一些迭代后的完整代码:

    namespace PipesAsyncAwait471
    {
        using System;
        using System.Collections.Generic;
        using System.IO;
        using System.IO.Pipes;
        using System.Linq;
        using System.Threading.Tasks;
    
        internal class Program
        {
            private const int MAX_REQUESTS = 1000;
    
            private static void Main()
            {
                var tasks = new List<Task> {
                    //Task.Run(() => HandleRequest(0))
                    HandleRequestAsync(0)
                };
    
                tasks.AddRange(Enumerable.Range(0, MAX_REQUESTS).Select(i => Task.Factory.StartNew(() => SendRequest(i), TaskCreationOptions.LongRunning)));
    
                Task.WhenAll(tasks);
    
                Console.ReadKey();
            }
    
            private static void HandleRequest(int counter)
            {
                try {
                    var server = new NamedPipeServerStream("MyPipe",
                                                        PipeDirection.InOut,
                                                        NamedPipeServerStream.MaxAllowedServerInstances,
                                                        PipeTransmissionMode.Message,
                                                        PipeOptions.Asynchronous);
    
                    Console.WriteLine($"Waiting a client... {counter}");
    
                    server.BeginWaitForConnection(WaitForConnectionCallback, server);
                }
                catch (Exception ex) {
                    Console.WriteLine(ex);
                }
    
                void WaitForConnectionCallback(IAsyncResult result)
                {
                    var server = (NamedPipeServerStream)result.AsyncState;
    
                    int index = -1;
    
                    try {
                        server.EndWaitForConnection(result);
    
                        HandleRequest(++counter);
    
                        if (server.IsConnected) {
                            var request = new byte[4];
                            server.BeginRead(request, 0, request.Length, ReadCallback, server);
                            index = BitConverter.ToInt32(request, 0);
                            Console.WriteLine($"{index} Request.");
    
                            var response = BitConverter.GetBytes(index);
                            server.BeginWrite(response, 0, response.Length, WriteCallback, server);
                            server.Flush();
                            server.WaitForPipeDrain();
                            Console.WriteLine($"{index} Pong.");
    
                            server.Disconnect();
                            Console.WriteLine($"{index} Disconnected.");
                        }
                    }
                    catch (IOException ex) {
                        Console.WriteLine($"{index}\n\t{ex}");
                    }
                    finally {
                        server.Dispose();
                    }
                }
    
                void ReadCallback(IAsyncResult result) 
                {
                    var server = (NamedPipeServerStream)result.AsyncState;
    
                    try {
                        server.EndRead(result);
                    }
                    catch (IOException ex) {
                        Console.WriteLine(ex);
                    }
                }
    
                void WriteCallback(IAsyncResult result) 
                {
                    var server = (NamedPipeServerStream)result.AsyncState;
    
                    try {
                        server.EndWrite(result);
                    }
                    catch (IOException ex) {
                        Console.WriteLine(ex);
                    }
                }
            }
    
            private static async Task HandleRequestAsync(int counter)
            {
                NamedPipeServerStream server = null;
    
                int index = -1;
    
                try {
                    server = new NamedPipeServerStream("MyPipe",
                                                    PipeDirection.InOut,
                                                    NamedPipeServerStream.MaxAllowedServerInstances,
                                                    PipeTransmissionMode.Message,
                                                    PipeOptions.Asynchronous);
    
                    Console.WriteLine($"Waiting a client... {counter}");
    
                    await server.WaitForConnectionAsync()
                                .ContinueWith(async t => await HandleRequestAsync(++counter).ConfigureAwait(false))
                                .ConfigureAwait(false);
    
                    if (server.IsConnected) {
                        var request = new byte[4];
                        await server.ReadAsync(request, 0, request.Length).ConfigureAwait(false);
                        index = BitConverter.ToInt32(request, 0);
                        Console.WriteLine($"{index} Request.");
    
                        var response = BitConverter.GetBytes(index);
                        await server.WriteAsync(response, 0, response.Length).ConfigureAwait(false);
                        await server.FlushAsync().ConfigureAwait(false);
                        server.WaitForPipeDrain();
                        Console.WriteLine($"{index} Pong.");
    
                        server.Disconnect();
                        Console.WriteLine($"{index} Disconnected.");
                    }
                }
                catch (IOException ex) {
                    Console.WriteLine($"{index}\n\t{ex}");
                }
                finally {
                    server?.Dispose();
                }
            }
    
            private static void SendRequest(int index)
            {
                NamedPipeClientStream client = null;
    
                try {
                    client = new NamedPipeClientStream(".", "MyPipe", PipeDirection.InOut, PipeOptions.None);
    
                    client.Connect();
    
                    var request = BitConverter.GetBytes(index);
                    client.Write(request, 0, request.Length);
                    client.Flush();
                    client.WaitForPipeDrain();
                    Console.WriteLine($"{index} Ping.");
    
                    var response = new byte[4];
                    client.Read(response, 0, response.Length);
                    index = BitConverter.ToInt32(response, 0);
                    Console.WriteLine($"{index} Response.");
                }
                catch (Exception ex) {
                    Console.WriteLine($"{index}\n\t{ex}");
                }
                finally {
                    client?.Dispose();
                }
            }
        }
    }
    
    namespace PipesAsyncAwait471
    {
    使用制度;
    使用System.Collections.Generic;
    使用System.IO;
    使用System.IO.Pipes;
    使用System.Linq;
    使用System.Threading.Tasks;
    内部课程计划
    {
    私有const int MAX_请求=1000;
    私有静态void Main()
    {
    var tasks=新列表{
    //Task.Run(()=>HandleRequest(0))
    HandlerRequestAsync(0)
    };
    tasks.AddRange(Enumerable.Range(0,最大请求数)。选择(i=>Task.Factory.StartNew(()=>SendRequest(i),TaskCreationOptions.LongRunning));
    任务。WhenAll(任务);
    Console.ReadKey();
    }
    专用静态无效句柄请求(int计数器)
    {
    试一试{
    var server=newnamedpipeserverstream(“MyPipe”,
    PipeDirection.InOut,
    NamedPipeServerStream.MaxAllowedServerInstances,
    PipeTransmissionMode.Message,
    管道选项(异步);
    WriteLine($“正在等待客户端…{counter}”);
    BeginWaitForConnection(WaitForConnectionCallback,server);
    }
    捕获(例外情况除外){
    控制台写入线(ex);
    }