如何让 C# WebSocketClient 持续监听消息

Posted

技术标签:

【中文标题】如何让 C# WebSocketClient 持续监听消息【英文标题】:How to get C# WebSocketClient to listen for messages in an ongoing capacity 【发布时间】:2020-02-14 04:34:11 【问题描述】:

我正在编写一个程序(实际上是 Unity 中的一个游戏),它应该充当一个单独启动并运行的 Websocket 服务器的客户端。

我正在使用System.Net.Websockets ClientWebSocket。我已经打开了连接,我可以发送消息,但与在 javascript 客户端中我将设置一个回调函数不同,该函数将在每次 websocket 客户端收到一条消息时运行我很难理解 C# 的预期流程API。

这是我编写的消息处理程序:

public async Task HandleMessages() 
        using (var ms = new MemoryStream()) 
            var messageBuffer = WebSocket.CreateClientBuffer(8192, 8192);
            WebSocketReceiveResult result;
            do 
                result = await ws.ReceiveAsync(messageBuffer, CancellationToken.None);
                ms.Write(messageBuffer.Array, messageBuffer.Offset, result.Count);
            
            while (!result.EndOfMessage);

            if (result.MessageType == WebSocketMessageType.Text) 
                var msgString = Encoding.UTF8.GetString(ms.ToArray());
                Debug.Log(msgString);
                var message = JsonConvert.DeserializeObject<Dictionary<String, String>>(msgString);
                if (message["roomCode"] == RoomCode.ToLower()) 
                    // Message was intended for us!
                    Debug.Log("[WS] Got a message of type " + message["messageType"]);
                
            
        
    

所以在最初打开我的 Websocket 连接后,如果我这样调用:

await Task.WhenAll(HandleMessages());

然后它将处理第一条传入消息,但不处理任何后续消息。我尝试了很多不同的方法,但我不知道如何在每次收到消息时运行此任务。

有人对此事有任何见解吗?

【问题讨论】:

我没有使用 websockets 的经验,但我认为result.EndOfMessage 表示何时收到完整的消息,而不是表示没有更多数据的潜力。 是的,表示该消息的结束。然而,另一条消息(实际上更多)将被发送,我需要在它们进来时处理它们 再次调用await ws.ReceiveAsync(... 不起作用吗? 它会,但 websocket 的重点是在发送消息时接收消息。每当从 websocket 服务器广播消息时,如何让整个处理程序作为回调函数(或 C#ey 等效概念)运行 似乎在这里你只需要一个while 循环? (大概在ms 范围内,只需确保在循环结束时将LengthPosition 设置为零) 【参考方案1】:

事实证明,在这种情况下,与往常一样,存在很好的用户错误因素。

我不了解 websockets 的一些基本概念,所以当我认为我正在从我的服务器广播消息时,我实际上只是将它们发送到某些客户端。随着 Marc Gravell 建议的改进和更多时间的修改,我的 C# 客户端代码现在看起来像这样:

public async Task HandleMessages() 
        try 
            using (var ms = new MemoryStream()) 
                while (ws.State == WebSocketState.Open) 
                    WebSocketReceiveResult result;
                    do 
                        var messageBuffer = WebSocket.CreateClientBuffer(1024, 16);
                        result = await ws.ReceiveAsync(messageBuffer, CancellationToken.None);
                        ms.Write(messageBuffer.Array, messageBuffer.Offset, result.Count);
                    
                    while (!result.EndOfMessage);

                    if (result.MessageType == WebSocketMessageType.Text) 
                        var msgString = Encoding.UTF8.GetString(ms.ToArray());
                        var message = JsonConvert.DeserializeObject<Dictionary<String, String>>(msgString);
                        if (message["roomCode"].ToLower() == RoomCode.ToLower()) 
                            Debug.Log("[WS] Got a message of type " + message["messageType"]);
                            // Message was intended for us!
                            switch (message["messageType"]) 
                                // handle messages here, unimportant to ***
                            
                        
                    
                    ms.Seek(0, SeekOrigin.Begin);
                    ms.Position = 0;
                
            
         catch (InvalidOperationException) 
            Debug.Log("[WS] Tried to receive message while already reading one.");
        
    

一旦我将服务器配置为实际广播我认为我正在广播的消息(遍历所有客户端并发送消息),它现在将读取多条消息。再次感谢您的帮助,希望这将有助于将来其他刚接触 websockets 的人有需要检查的东西

【讨论】:

以上是关于如何让 C# WebSocketClient 持续监听消息的主要内容,如果未能解决你的问题,请参考以下文章

如何使用带有 SSL 的 Spring WebSocketClient?

使用 tech.gusavila92.websocketclient.WebSocketClient 时出现证书错误

org.java_websocket.client.WebSocketClient.run 处的 java.lang.AssertionError(WebSocketClient.java:190)

android怎样使用websocketclient

Netty-源码分析WebSocketClient客户端

Jetty websocket 客户端类 WebSocketClient 线程安全吗?