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);
}