我正在制作一个简单的服务器来监听客户端,该服务器将读取客户端请求、进行一些计算、将响应发送回客户端并尽快再次关闭(有点类似于 HTTP)。
每秒钟可能有很多连接,所以我希望它尽可能快速和高效。
到目前为止,我能想到的最好的方法如下所示:
private static ManualResetEvent gate = new ManualResetEvent(false);
static async void ListenToClient(TcpListener listener)
{
Console.WriteLine("Waiting for connection");
TcpClient client = await listener.AcceptTcpClientAsync();
Console.WriteLine("Connection accepted & establised");
gate.Set(); //Unblocks the mainthread
Stream stream = client.GetStream();
byte[] requestBuffer = new byte[1024];
int size = await stream.ReadAsync(requestBuffer, 0, requestBuffer.Length);
//PSEUDO CODE: Do some calculations
byte[] responseBuffer = Encoding.ASCII.GetBytes("Ok");
await stream.WriteAsync(responseBuffer, 0, responseBuffer.Length);
stream.Close();
client.Close();
}
static void Main(string[] args)
{
TcpListener listener = new TcpListener(IPAddress.Any, 8888);
listener.Start();
while (true)
{
gate.Reset();
ListenToClient(listener);
gate.WaitOne(); //Blocks the main thread and waits until the gate.Set() is called
}
}
注意:为了这个例子和简单性,我没有像 try-catch 那样进行任何错误处理,我知道这里的响应总是“Ok”
这里的代码只是简单地等待一个连接,当它到达await listener.AcceptTcpClientAsync()
时,它会跳回到whileloop并等待直到建立连接并且gate.Set( ) 被调用以便它可以再次监听新连接。所以这将同时允许多个客户端(特别是如果计算可能需要很长时间)
但是我应该改用 stream.ReadAsync() 还是 stream.Read()?我很好奇它是否重要,因为我已经在一个不会阻塞主线程的异步函数中。
所以我最后的问题是:
- 这是完成此任务的最佳/正确方法吗(也使用 ManualResetEvent 类)?
- 在这种情况下,在读取和写入流时使用异步或非异步操作会有什么不同吗? (因为我没有阻塞主线程)
- 如果它滞后,发送/接收数据需要 1-2 秒,在异步和非异步操作之间进行选择是否仍然重要?
新改进的更新
由于回答,我已将我的代码更新为:
private static ManualResetEvent gate = new ManualResetEvent(false);
static async Task ListenToClient(TcpListener listener)
{
//Same Code
}
static void Main(string[] args)
{
TcpListener listener = new TcpListener(IPAddress.Any, 8888);
listener.Start();
while (true)
{
gate.Reset();
Task task = ListenToClient(listener);
task.ContinueWith((Task paramTask) =>
{
//Inspect the paramTask
});
gate.WaitOne(); //Blocks the main thread and waits until the gate.Set() is called
}
}
最佳答案
我立即看到两个常见的 async
错误:
async void
不要这样做。编译器甚至支持 async void
的唯一原因是为了处理现有的事件驱动接口(interface)。这不是其中之一,所以这是一个反模式。 async void
实际上会导致失去任何响应该任务或对其执行任何操作的方式,例如处理错误。
说到响应任务...
ListenToClient(listener);
您正在生成一个任务,但从未检查它的状态。如果该任务中出现异常,您会怎么做?无论如何它都没有被捕获,它只会被默默地忽略。至少您应该在任务完成后为其提供顶级回调。甚至像这样简单的事情:
ListenToClient(listener).ContinueWith(t =>
{
// t is the task. Examine it for errors, cancelations, etc.
// Respond to error conditions here.
});
关于c# - 在异步函数中使用异步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24436021/