ClientWebSocket 示例挂起

Posted

技术标签:

【中文标题】ClientWebSocket 示例挂起【英文标题】:ClientWebSocket example hangs 【发布时间】:2020-02-11 16:23:27 【问题描述】:

下页显示的示例不起作用: Using c# ClientWebSocket with streams

它挂在下面一行:

等待 ws.ConnectAsync(serverUri, CancellationToken.None);

似乎没有建立连接。

请指出使以下代码工作的最简单修改。我不想使用任何第三方工具或库。

private static async Task DoClientWebSocket()

    using (ClientWebSocket ws = new ClientWebSocket())
    
        Uri serverUri = new Uri("wss://echo.websocket.org/");
        await ws.ConnectAsync(serverUri, CancellationToken.None);
        while (ws.State == WebSocketState.Open)
        
            string msg = "hello123";
            ArraySegment<byte> bytesToSend = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msg));
            await ws.SendAsync(bytesToSend, WebSocketMessageType.Text, true, CancellationToken.None);
            ArraySegment<byte> bytesReceived = new ArraySegment<byte>(new byte[1024]);
            WebSocketReceiveResult result = await ws.ReceiveAsync(bytesReceived, CancellationToken.None);
            Console.WriteLine(Encoding.UTF8.GetString(bytesReceived.Array, 0, result.Count));
        
    

【问题讨论】:

如果我转到websocket.org/echo.html,并查看示例,URI 是ws://echo.websocket.org,而不是wss://echo.websocket.org/。糟糕,我看到了两个 URI。 我尝试了 ws: 和 wss:。两者都在 javascript 中工作,在 c# 中都没有。 你让事情变得非常困难。 c# 中的默认请求标头与其他应用程序不同。通常要使代码正常工作,您必须添加缺少的标头或修改默认标头。解决问题的最佳方法是比较 java 或使用嗅探器与非工作应用程序一起工作的。将第一个请求与 java 和 c# 进行比较。 没有在 javascript 中添加标头:websocket = new WebSocket(wsUri);我必须在 C# 中添加哪些标头? 【参考方案1】:

你是对的。您无需添加任何标题即可使用wss://echo.websocket.org/。你的代码在我结束时运行得很好。但我会建议一项改进,为您的ConnectAsyncSendAsyncReceiveAsync 调用包括timeout,这样它就不会长时间卡住。

我已将代码限制为仅调用 SendAsync 5 次,以便更容易验证输出。

[已编辑:] 包含通过多次调用 `ReceiveAsync 来接收完整响应的逻辑。

private static async Task DoClientWebSocket()

    using (ClientWebSocket ws = new ClientWebSocket())
    
        Uri serverUri = new Uri("wss://echo.websocket.org/");

        //Implementation of timeout of 5000 ms
        var source = new CancellationTokenSource();
        source.CancelAfter(5000);

        await ws.ConnectAsync(serverUri, source.Token);
        var iterationNo = 0;
        // restricted to 5 iteration only
        while (ws.State == WebSocketState.Open && iterationNo++ < 5)
        
          string msg = "hello0123456789123456789123456789123456789123456789123456789";
          ArraySegment<byte> bytesToSend =
                      new ArraySegment<byte>(Encoding.UTF8.GetBytes(msg));
          await ws.SendAsync(bytesToSend, WebSocketMessageType.Text,
                               true, source.Token);
          //Receive buffer
          var receiveBuffer = new byte[200];
          //Multipacket response
          var offset = 0;
          var dataPerPacket = 10; //Just for example
          while (true)
          
              ArraySegment<byte> bytesReceived =
                        new ArraySegment<byte>(receiveBuffer, offset, dataPerPacket);
              WebSocketReceiveResult result = await ws.ReceiveAsync(bytesReceived,
                                                            source.Token);
              //Partial data received
              Console.WriteLine("Data:0",
                               Encoding.UTF8.GetString(receiveBuffer, offset,
                                                            result.Count));
              offset += result.Count;
              if (result.EndOfMessage)
                    break;
            
            Console.WriteLine("Complete response: 0",
                                Encoding.UTF8.GetString(receiveBuffer, 0,
                                                            offset));
        
    



static void Main(string[] args)

    var taskWebConnect = Task.Run(() => DoClientWebSocket());

    taskWebConnect.Wait();

命令提示符的输出:

Data:hello01234
Data:5678912345
Data:6789123456
Data:7891234567
Data:8912345678
Data:9123456789
Complete response: hello0123456789123456789123456789123456789123456789123456789

【讨论】:

@Tester 很高兴知道。乐意效劳。您可以通过点击答案窗口左侧的Tick 符号来接受答案。 现在我需要从不同的 WebSocket 检索 100k。当我将 'ArraySegment(new byte' 的大小增加到 1024000 时,它仍然只检索 12K。你可以修改你的代码示例以检索最多 1MB 吗? @Tester 您可以使用从ReceiveAsync 收到的响应的EndOfMessage 属性多次读取,直到读取所有数据。我会更新代码来解决它。

以上是关于ClientWebSocket 示例挂起的主要内容,如果未能解决你的问题,请参考以下文章

ClientWebSocket.ConnectAsync 崩溃,没有任何错误信息

强制 HttpWebRequest 和 ClientWebSocket 使用 TLS 1.2

使用 ClientWebSocket .net 核心测试 TestHost.WebSocketClient

Xamarin Mono ClientWebSocket 实现不适用于安全套接字

System.Net.WebSockets.ClientWebSocket 不能可靠地工作?

ClientWebsocket SSL 证书验证失败