ClientWebSocket.ConnectAsync 立即关闭

时间:2021-02-25 19:38:54

标签: c# websocket

我正在实现一个小的 ClientWebSocket 来将消息发送到计算机的 IPAddress.Loopback 地址,以便浏览器实用程序页面可以接收它们。但是,一旦我连接,客户端就会立即关闭,没有消息、原因或异常。

ClientWebSocket cws;
Uri address = new Uri("ws://" + IPAddress.Loopback.ToString() + ":80/"

async void Start(){
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls |
        SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

    using (cws = new ClientWebSocket()) {
        cws.Options.KeepAliveInterval = new TimeSpan(1, 0, 0);

        //Start response listener loop
        _ = Task.Run(() => async_ListenerLoop(receiveCancelTokenSrc.Token).ConfigureAwait(false));
        
        try {
            //Start the connection
            cws.ConnectAsync(address, sendCancelTokenSrc.Token);

        } catch(Exception ex) {
            MessageBox.Show("Unable to connect.\n\r\n\r" + ex.Message);
        }
    }
}


async Task async_ListenerLoop(CancellationToken cancelToken) {
    ArraySegment<byte> buffer = WebSocket.CreateServerBuffer(RECIEVE_BUFFER);
    List<byte> rawData = new List<byte>();

    try {
        while (state != WebSocketState.Closed && state != WebSocketState.Aborted && !cancelToken.IsCancellationRequested) {
            if(state == WebSocketState.Connecting) {
                //Sometimes it waits 2-3 cycles, other times it closes immediately              
                await Task.Delay(500);
                continue;
            }

            WebSocketReceiveResult receiveResult = await cws.ReceiveAsync(buffer, cancelToken);

            if (!cancelToken.IsCancellationRequested) {
                if (state == WebSocketState.CloseReceived && receiveResult.MessageType == WebSocketMessageType.Close) {
                    sendCancelTokenSrc.Cancel();

                    await cws.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Acknowledge Close frame", CancellationToken.None);
                    //The socket state changes to closed at this point
                }

                if (state == WebSocketState.Open) {
                    if (receiveResult.MessageType == WebSocketMessageType.Text) {
                        rawData.AddRange(buffer.Array);
                            
                        if (receiveResult.EndOfMessage) {
                            string strData = Encoding.UTF8.GetString(rawData.ToArray(), 0, rawData.Count);
                            ProcessData(JsonConvert.DeserializeObject<RequestDigest>(strData));
                            rawData.Clear();
                        }

                    } else if (receiveResult.MessageType == WebSocketMessageType.Binary) {
                        rawData.AddRange(buffer.Array);

                        if (receiveResult.EndOfMessage) {
                            ProcessData(rawData.ToArray());
                            rawData.Clear();
                        }
                    }
                }
            }
        }
        //Descripion is always null
        MessageBox.Show("Connection was closed because '"+cws.CloseStatusDescription+"'");

        } catch (OperationCanceledException ex) {
            // normal upon task/token cancellation, disregard
            MessageBox.Show("Connection to server cancelled.\n\r\n\r" + ex.Message);

        } catch (JsonReaderException ex) {
            MessageBox.Show("Unable to read incoming message.\n\r\n\r" + ex.Message);

        } catch (Exception ex) {
            MessageBox.Show("Unable recieve incoming message.\n\r\n\r" + ex.Message);

        } finally {
            sendCancelTokenSrc.Cancel();
            AbortConnection();
        }
    }
    
void AbortConnection() {
    // don't leave the socket in any potentially connected state
    if (state != WebSocketState.Closed) {
        cws.Abort();
    }
    cws.Dispose();
}

1 个答案:

答案 0 :(得分:0)

您的代码可能还有其他问题(连接套接字和客户端需要一些麻烦才能搞定),但有两个明显的问题:

您需要等待 ConnectAsync(...) 的结果,才能停止 Start() 的代码在没有它的情况下同步继续:

await cws.ConnectAsync(address, sendCancelTokenSrc.Token);

并且您需要确保 cws 在完成之前不会被处理掉。 using(cws) { ... } 块将在代码离开花括号(当前立即发生)时处理 cws,即使您的侦听器仍在运行,并且需要它保持活动状态。

您可以通过等待异步结果(例如提示!来自您的侦听器的最终结果)将代码保留在 using 块中来实现此目的,或者不使用 { {1}} 并在适当的时间手动处理 using

还要确保仅在连接调用完成后才启动侦听器,以确保 cws 处于良好状态。

像这样:

cws

而且……您的听众无疑也需要做更多的工作,但以上内容将使您解决眼前的问题(希望如此!)

相关问题