c# - 如何将 websocket 连接解码为 json 流?

标签 c# .net json websocket .net-core

我的客户端正在连接到一个 websocket 服务器,并且通信都是 json 格式。我用 ClientWebSocket及其 ReceiveAsync记录的方法。我的读取循环是这样的:

byte[] data = new byte[4096];
ArraySegment<byte> buffer = new ArraySegment<byte>(data);
readLoopTask = Task.Run(async () =>
{
    while (true)
    {
        var result = await socket.ReceiveAsync(buffer, CancellationToken.None);
        if (result.Count > 0)
        {
            string m = Encoding.ASCII.GetString(data, 0, result.Count);
            ProcessMessage(m); // decode json string
        }
        else
        {
            Console.WriteLine("recved zero:", result);
            break;
        }
    }
}, token);

我发现这个实现的问题是服务器传递的一些 json 对象非常大,无法放入缓冲区,在这种情况下,读取的输入被截断并且不是有效的 json 字符串,因此解码失败。

有人可能会争辩说我可以继续读取 websocket 直到读取一个完整的 json 对象,但这会导致一个非常复杂的解决方案并且需要手动处理 json 字符串,因为我将不得不检查每个字节并搜索json 字符串。我还需要保留之后的部分,因为它是下一个 json 对象的开始部分。

我的问题是,为什么 WebSocket 没有将其网络流导出给用户,就像 TcpClient.GetStream 一样确实,在 TcpClient 的情况下,处理这种情况会很容易,只需将流提供给 json 解码器即可:

Stream stream = tcpClient.GetStream();
JsonDecoder decoder = new JsonDecoder(stream);
Object obj;
while (true) {
    decoder.Decode(obj);
    // handle obj
}

那么在目前没有这样的API的情况下,有没有更好的方法来解决这个问题呢?

最佳答案

好吧,终于发现这不是一个值得担心的问题。关键是ClientWebSocket.ReceiveAsync会返回一个WebSocketReceiveResult,里面有EndOfMessage,是一个 bool 标志,表示这部分数据是不是消息结束,所以通常的操作是连续接收直到标志为真,然后将所有累积的数据提供给 json 解码器。

WebSocketReceiveResult result = null;
while(running) {
    do {
        result = await socket.ReceiveAsync(buffer, cts.Token).ConfigureAwait(false);
        if (result.Count > 0)
        {
             memStream.Write(buffer.Array, buffer.Offset, result.Count);
        }
        else
        {
             logger.LogWarning("WS recved zero: {0}, {1}", result.Count, socket.State);
             break;
        }
    } while (!result.EndOfMessage); // check end of message mark
}

关于c# - 如何将 websocket 连接解码为 json 流?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44738862/

相关文章:

java - 仅从每个 Java 文件顶部删除多行注释

c# - Android 模拟器未运行 - Visual Studio 2017

.net - XDocument内存使用问题

c# - .NET:由于事务超时导致的异步回滚

.net - 当我在 azure 上添加 HTTP(S) 时 ssl 安全吗?

javascript - 从php服务器读取json

c# - Unity3D 新的 UI 系统和 ListView

c# - 在运行空间中导入或加载模块,仍然 'Connect-AzureRMAccount' 抛出 'command not recognised as cmdlet..'

ios - Objective-c 中的 NSTaggedPointerString objectForKey

javascript - 如何解析从 javascript 或 jquery 中的 php 脚本检索的 json 数据