WebSocket通信问题排查及优化
扫描二维码随身看资讯
使用手机 二维码应用 扫描右侧二维码,您可以
1. 在手机上细细品读~
2. 分享给您的微信好友或朋友圈~
项目中遇到了WebSocket超时问题。具体情况是在OTA升级过程中,解压zip文件会产生解压进度事件,然后将解压进度通过进程通信传递给另一进程,但通信过程中出现了超时异常。
我们发现在解压大文件时,解压进度事件的触发间隔竟然是1毫秒,这个频率实在是太高了。
然而,即使解压事件频率高,也不应该导致通信异常。因此,我进行了定时发送通信事件的测试,以验证进程间通信流程。
WebSocketSharp
当前项目中使用的进程间通信组件是基于kaistseo/UnitySocketIO-WebSocketSharp实现的。在该组件中,我们在主机内设置了一个服务端,并允许多个客户端连接到服务端。客户端之间的通信由服务端来转发数据。具体流程是客户端A发送信息给客户端B,然后客户端B将执行结果反馈给客户端A。
在排查问题时,我们发现各个链路的发送延时都是正常的,包括服务端发送反馈数据给客户端A。然而,客户端A接收数据的延时却非常大。以下是部分返回数据的示例:
并且随着通信时间的增加,延时会变得越来越大。
在查看WebSocketSharp.WebSocket对外事件OnMessage时,我们发现OnMessage是由WebSocket.message()触发的,从_messageEventQueue队列中获取数据。
在循环接收数据时,我们发现了ManualResetEvent。考虑到数据量很大,这里使用了同步信号锁,这必然会导致阻塞。
为什么要设置线程同步锁呢?我们继续深入了解。
WebSocketSharp的数据发送是基于TCPClient实现的。在初始化后,通过_stream.Write (bytes, 0, bytes.Length)来发送数据。
而接收数据则是通过_stream进行读取。可以在startReceiving()方法中看到,使用了WebSocketFrame.ReadFrameAsync (_stream, false,...)来进行数据读取。
我们知道,TCP是面向连接的,提供可靠、顺序的数据流传输。它适用于一对一的通信,即一个TCP连接只能有一个发送方和一个接收方。更多细节可以参考之前我写的文章:.NET TCP、UDP、Socket、WebSocket - 唐宋元明清2188 - 博客园 (cnblogs.com)
然而,在高并发场景下,适当的同步措施仍然是必需的。我们可以使用lock,也可以使用SemaphoreSlim来实现复杂的同步需求。而在这里,使用的是信号锁ManualResetEvent。
再来看看发送端的代码,同样也使用了lock来限制并发操作。
因此,在高并发场景下,WebSocketSharp存在通信阻塞问题。当然,WebSocketSharp已经做得很好了,正常情况下几毫秒内是不会遇到阻塞问题的。例如,设置了3毫秒的定时超频发送后,发送一段时间后的效果如下:
客户端A发送消息,由服务端转发至客户端B,再将客户端B的反馈结果由服务端转发回客户端A,真正的延时只有0-2毫秒!
因此,在项目中遇到的ZIP文件解压进度超快1毫秒的问题,我们需要对zip解压处进行优化,设置并发操作10毫秒内保留最后一个操作。可以参考.NET异步并发操作,只保留最后一次操作 - 唐宋元明清2188 - 博客园 (cnblogs.com),即在10毫秒内最多触发一次解压进度事件。确实,这样的优化也是有必要的,即使通信能够承受这种高并发,UI刷新如此高的帧率也会浪费CPU/GPU资源。
WebSocket
接下来,我们再来看看原生的WebSocket,并编写一个WebSocket通信Demo kybs00/WebSocketDemo (GitHub.com)。
在该Demo中,服务端定时1毫秒向客户端发送Message消息,结果竟然是:
System.InvalidOperationException:“There is already one outstanding 'SendAsync' call for this WebSocket instance. ReceiveAsync and SendAsync can be called simultaneously, but at most one outstanding operation for each of them is allowed at the same time.”
看来发送事件外部也要处理好高并发的场景,1毫秒真的是太猛了。
加上信号量同步后,服务端就能正常发送了。以下是10分钟后客户端接收数据打印的结果,传输几乎没有延时:
此外,我们还尝试了在客户端接收数据时添加信号量同步,但仍然提示服务端发送不支持并行操作的异常。
因此,在发送端加入需要串行处理的信号量,例如上面提到的SemaphoreSlim,以确保完整地写入数据并执行_stream.FlushAsync()。
- 菇菇栽培研究室(World)
- 疑点重重 免广告版
- 时光杂货店官方版
- 生存战争2联机版(Survivalcraft 2 Day One)
- 归途24小时正版
- 提莫卡的午夜
- 热血樱校
- 从细胞到奇点(Cells)
- 卡车人生破解版
- 飞机大厨 官方正版下载最新版
- 魅魔模组(原珍妮模组)安装包
- 怪物守护者
- 植物大战僵尸乱斗版
- Decor Blast
- C#/.NET/.NET Core技术前沿周刊
- 使用Kiota工具在.NET环境下生成WebApi代理类
- C#/.NET/.NET Core优秀项目和框架2024年6月简报
- 使用.NET中的System.IO.Compression进行文件和文件夹压缩的方法
- 开源.NET绘图库OxyPlot的跨平台应用
- 深度优化分布式缓存性能:微软推出.NET9中的HybridCache解决方案
- Asp .Net Core 系列:详解鉴权(身份验证)以及实现 Cookie、JWT、自定义三种鉴权 (含源码解析)
- C#.Net筑基-深入解密小数内部存储的秘密
- OpenTelemetry 简介及在.NET中使用OpenTelemetry logs对接Seq的示例
- 介绍.NET Aspire:简化.NET云原生应用程序的构建和管理
- 深入了解Channel类:.NET CORE 3.0的新特性
- 在Kylin操作系统上部署.NET Core 6.0项目的步骤和方法
- 1
蛋仔派对 网易版官服
- 2
吸血吧
- 3
我的钓鱼生活手游
- 4
夏哈塔遭难的一天 官方正版
- 5
宝宝学颜色小游戏(更名宝宝玩颜色)
- 6
2048清手游
- 7
超市模拟器 正版
- 8
继续说不会炸 中文版
- 9
违和感推理游戏
- 10
人类游乐场 安卓免费版