[英]Mixing async-await with fire-and-forget approach
我正在使用.NET的HttpListener
类编写Websocket服务器。
本质上,我有一个HandleListener()
函数,它等待客户端连接并将每个客户端生成给HandleClient(WebSocket client)
。 所以我目前有:
private async void HandleListener()
{
try
{
while (listener != null && listener.IsListening)
{
HttpListenerContext listenerContext = await listener.GetContextAsync();
WebSocketContext webSocketContext = await listenerContext.AcceptWebSocketAsync(subProtocol: null);
WebSocket webSocket = webSocketContext.WebSocket;
clients.Add(webSocket);
await HandleClient(webSocket);
}
}
catch (HttpListenerException) { } // Got here probably because StopWSServer() was called
}
private async Task HandleClient(WebSocket client) { ... }
问题是,我似乎无法处理一个以上的客户。 只要连接了第一个客户端, HandleListener()
的执行就HandleListener()
暂停。
我尝试从对HandleClient()
的调用中删除await
,但是出现“因为未等待此调用...”错误。 我可以使HandleClient()
成为async void
方法,但这不是事件处理程序。
顺便说一句, HandleClient()
是async Task
的原因是因为它一直在循环执行,直到侦听器死机为止:
recieveResult = await client.ReceiveAsync(recievedBuffer, CancellationToken.None);
据我了解,一劳永逸的做法总体上是不好的,而且我似乎无法通过async-await实现来实现。 但是HandleClient()
是 HandleClient()
方法,而且我看不到任何其他实现我所需要的方法的方法。
编辑:添加了HandleClient()
当前实现:
private async Task HandleClient(WebSocket client)
{
try
{
ArraySegment<byte> recievedBuffer = new ArraySegment<byte>(new byte[BUFFER_SIZE]);
while (listener != null && listener.IsListening && client.State == WebSocketState.Open)
{
WebSocketReceiveResult recieveResult;
using (var ms = new MemoryStream())
{
do
{
recieveResult = await client.ReceiveAsync(recievedBuffer, CancellationToken.None);
ms.Write(recievedBuffer.Array, recievedBuffer.Offset, recieveResult.Count);
}
while (!recieveResult.EndOfMessage);
switch (recieveResult.MessageType)
{
case WebSocketMessageType.Close:
RemoveClient(client, WebSocketCloseStatus.NormalClosure, string.Empty);
break;
case WebSocketMessageType.Binary:
RemoveClient(client, WebSocketCloseStatus.InvalidMessageType, "Cannot accept binary frame");
break;
case WebSocketMessageType.Text:
OnRecieve?.Invoke(client, System.Text.Encoding.UTF8.GetString(ms.ToArray()));
break;
}
}
}
}
catch (WebSocketException ex)
{
RemoveClient(client, WebSocketCloseStatus.InternalServerError, ex.Message);
}
}
之所以会这样,是因为您为此编写了代码,我的意思是说您编写了如下方法。
private async void HandleListener()
{
try
{
while (listener != null && listener.IsListening)
{
HttpListenerContext listenerContext = await listener.GetContextAsync();
WebSocketContext webSocketContext = await listenerContext.AcceptWebSocketAsync(subProtocol: null);
WebSocket webSocket = webSocketContext.WebSocket;
clients.Add(webSocket);
await HandleClient(webSocket);
}
}
catch (HttpListenerException) { } // Got here probably because StopWSServer() was called
}
在这种方法中,当遇到await
控件时,控制权将返回给原始呼叫者,直到您等待的部分完成并在此之后开始下一次调用。
检查下图,这是如何等待和异步的
如果你只是想生火而忘了尝试
private void HandleListener()
{
try
{
while (listener != null && listener.IsListening)
{
HttpListenerContext listenerContext = await listener.GetContextAsync();
WebSocketContext webSocketContext = await listenerContext.AcceptWebSocketAsync(subProtocol: null);
WebSocket webSocket = webSocketContext.WebSocket;
clients.Add(webSocket);
HandleClient(webSocket);
}
}
catch (HttpListenerException) { } // Got here probably because StopWSServer() was called
}
这意味着不要等待任务完成
为防止编译器警告,请使用如下方法:
public static class TaskExtensions {
public static void Forget(this Task task) {
}
}
然后做
HandleClient(webSocket).Forget()
如果走这条路,请确保以某种方式处理HandleClient
所有异常(例如,将整个内容包装到try-catch中)。 在这种情况下,这种方法没有内在的“坏处”。
另一种方法是:
HandleClient(webSocket).ContinueWith(task => {
if (task.IsFaulted && task.Exception != null) {
// handle it here
}
});
如您所见,在这种情况下,等待HandleClient
是HandleClient
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.