私は、.NETのHttpListener
クラスを使用してwebsocketサーバーを作成しています。async-awaitとfire-and-forgetのアプローチを組み合わせる
本質的には、クライアントが接続して各クライアントをHandleClient(WebSocket client)
にするのを待つHandleListener()
機能があります。だから、私は現在持っている:
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()
の実行が停止しているようです。
を電話番号HandleClient()
に転送しようとしましたが、「この電話は待たれていないため」というエラーが表示されます。私はHandleClient()
をasync void
メソッドにすることができますが、これはイベントハンドラではありません。それはループ内ですべての上に、やっているので、リスナーが死んでいるまで
はところで、HandleClient()
がasync Task
であることの理由は次のとおりです。
recieveResult = await client.ReceiveAsync(recievedBuffer, CancellationToken.None);
私が理解から、ファイア・アンド・フォーゲットアプローチは、全体的に悪く、非同期の実装では実現できないようです。しかし、HandleClient()
はであり、私は必要なものを達成する他の方法は見当たりません。
EDIT: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);
}
}
「HandleClient」とは何ですか?あなたはそれが火であり、忘れていると言います。しかし、なぜ非同期ですか? – Sefe
これは '... await client.ReceiveAsync ... 'をループ内で行うため、非同期です。私はこれを含めるために質問を編集しました。 – galah92
しかしそれは火ではなく、忘れている。受信が完了するのを待っているときは、あなたは忘れていません。問題はあなたのコードの構造にあるようです。 'HandleClient'からの1行は、それを解決するのに十分ではありません。 – Sefe