我对服务器/客户端架构有以下要求:
因此,考虑到以下要求,我编写了以下代码,但我不太确定,因为管道的文档有些缺乏,不幸的是,代码似乎无法正常工作,它在某个点挂起.
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!");
}
}
}
}
}
假设:
我期望它工作的方式是当我调用
SendRequestAsync
并发执行时我发出的所有请求,然后每个请求发出额外的请求,直到它到达 6
,最后,它应该打印“完成!”。备注:
最佳答案
断开连接时,WaitForPipeDrain()
可能会因管道损坏而抛出 IOException
。
如果这发生在您的服务器 Task
中,那么它将永远不会监听下一个连接,并且所有剩余的客户端连接都卡在 ConnectAsync()
上。
如果这发生在其中一个客户端任务中,则它不会继续递归并增加该索引的计数器。
如果您将 WaitForPipeDrain()
的调用包装在 try
/catch
中,程序将永远运行,因为您的函数 HandleRequestAsync()
是无限递归的。
简而言之,要让它发挥作用:
IOException
WaitForPipeDrain()
HandleRequestAsync()
必须在某个时候完成。