Как справиться с близким рукопожатием c# - PullRequest
1 голос
/ 09 июля 2020

Я разработал игру в догадки в c# с использованием веб-сокетов и вызовов https. Каждый раз, когда пользователь создает экземпляр консольного приложения для воспроизведения, он подключается к серверу. (await webSocket.ConnectAsyn c (new Uri ("ws: // localhost: xxx"), CancellationToken.None);).

У меня есть класс websocketmiddlewear для принятия запроса websocket и класс менеджера где я обрабатываю запросы веб-сокетов. Все работает нормально, кроме случаев, когда пользователь выходит из консольной игры. Например, когда я нажимаю «x» на консоли (cmd), я получаю следующую ошибку:

Удаленная сторона закрыла соединение WebSocket, не завершив рукопожатие закрытия.

в следующей строке

WebSocketReceiveResult result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); 

Почему код не обрабатывает ошибку и как ее исправить?

ConnectionManagerService.cs

 public async Task Receive(WebSocket socket)
        {
            var buffer = new byte[1024 * 4];

            while (socket.State == WebSocketState.Open)
            {
                WebSocketReceiveResult result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);


               if (result.MessageType == WebSocketMessageType.Text)
                {
                    Console.WriteLine($"Receive->Text");      
                    return;   
                }
                else if (result.MessageType == WebSocketMessageType.Close)
                {
                    string id = _sockets.FirstOrDefault(s => s.Value == socket).Key;
                    //Console.WriteLine($"Receive->Close on: " + id);

                    _sockets.TryRemove(id, out socket);
                    Console.WriteLine("Managed Connections: " + _sockets.Count.ToString());

                    await socket.CloseOutputAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
                    return;
                }
            }
        }
 

WebsocketMiddleware.cs

        }
        public async Task Invoke(HttpContext context)
        {
            var isSocketRequest = context.WebSockets.IsWebSocketRequest;
            if (isSocketRequest)
            {
                WebSocket socket = await context.WebSockets.AcceptWebSocketAsync();   
                _manager.AddSocket(socket);    
                await _manager.Receive(socket);

            }
            else
            {
                await _next(context);
            }
        }

1 Ответ

1 голос
/ 09 июля 2020

Это происходит потому, что вы обрабатываете только постепенное отключение соединения. Клиент может просто отключиться, и вы получите ol SocketIO Exception в середине операции read/write.

Рассмотрите возможность упаковки вашего Socket операции в try-catch и выполняйте их по своему усмотрению.

public async Task Receive(WebSocket socket)
        {
            var buffer = new byte[1024 * 4];
            try{
                while (true) 
                {
                    WebSocketReceiveResult result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                    if (result.MessageType == WebSocketMessageType.Text)
                    {
                        Console.WriteLine($"Receive->Text");      
                        return;   
                    }
                    else if (result.MessageType == WebSocketMessageType.Close)
                    {
                    string id = _sockets.FirstOrDefault(s => s.Value == socket).Key;
                    //Console.WriteLine($"Receive->Close on: " + id);

                    _sockets.TryRemove(id, out socket);
                    Console.WriteLine("Managed Connections: " + _sockets.Count.ToString());

                    await socket.CloseOutputAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
                    return;
                    }
                } 
            } catch(Exception ex){   //not so graceful disconnect
                 _sockets.TryRemove(id, out socket);
                    //deal with closed connection 
                    //maybe reconnect ?
            }
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...