【问题标题】:Abnormal closure of WebSocket does not return ReceiveAsyncWebSocket 异常关闭不返回 ReceiveAsync
【发布时间】:2018-01-28 21:48:54
【问题描述】:

我在服务器上有一个线程,用于处理通过 WebSocket 连接从客户端接收到的数据:

    public HttpResponseMessage Get()
    {
        if (HttpContext.Current.IsWebSocketRequest)
        {
            HttpContext.Current.AcceptWebSocketRequest(ProcessWebSocket);
        }

        return new HttpResponseMessage(HttpStatusCode.SwitchingProtocols);
    }

    private async Task ProcessWebSocket(AspNetWebSocketContext context)
    {
        WebSocket webSocket = context.WebSocket;    //Gets the current WebSocket object. 
        const int maxMessageSize = 1024;
        byte[] receivedDataBuffer = new byte[maxMessageSize];
        logger.Debug("WSC-New WebSocket connection");
        while (webSocket.State == WebSocketState.Open)
        {
            var timeOut = new CancellationTokenSource(70000).Token;
            WebSocketReceiveResult webSocketReceiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(receivedDataBuffer), timeOut);
            //If input frame is cancelation frame, send close command. 
            if (webSocketReceiveResult.MessageType == WebSocketMessageType.Close)
            {
                await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, String.Empty, CancellationToken.None);
                logger.Debug("WSC-Close WebSocket connection frame received");
            }
            else
            {
                //Process received data....
            }
        }
        logger.Debug("WSC-WebSocket closed, WebSocket state: {0}", webSocket.State.ToString());
    }

只要对方正确关闭了 WebSocket 连接,我就会在最后收到记录器消息,指出 WebSocket 已关闭,这意味着该线程正确终止。如果客户端进入睡眠状态或程序突然停止,则不会发生正常的 WebSocket 关闭。在这种情况下 webSocket.ReceiveAsync 永远不会返回。我担心如果启动了足够多的这些线程但从未终止,我可能会出现严重的内存泄漏。超时取消令牌应该让它在 70 秒后返回,但它没有发生。如果我在这种情况下尝试从另一个线程访问 webSocket 对象,则会收到以下异常:无法访问已处置的对象。

我怎样才能从 await webSocket.ReceiveAsync(new ArraySegment(receivedDataBuffer), timeOut);正确关闭此线程?

【问题讨论】:

标签: c# websocket


【解决方案1】:

问题:

突然关闭几乎所有连接都会导致另一个套接字永远无法获取更多数据,这会导致您的套接字像您说的那样保持打开状态。

解决方案:

尝试使用 Keep-Alive 来决定连接何时超时,另一种解决方案是使用一个单独的线程,该线程可能会被终止以丢弃它,但我不确定它对你的效果如何。

启动套接字 EX:

Thread X = new Thread(() => {
    Connect();
});
X.Start();

结束套接字 EX:

X.Abort();
// You could also force a Garbage Collection using
GC.Collect();

【讨论】:

  • keep alive 默认设置为 30 秒,这似乎并没有真正做任何事情,我的猜测是即使您的网站不再运行,IIS/IIS express 也会保持保持活动状态,您可以使用线程(甚至更好的取消令牌)硬杀死您的套接字,但是您无法知道它没有要发送和它消失之间的区别。
猜你喜欢
  • 2021-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
相关资源
最近更新 更多