基于 websocket 实现的 im 实时通讯案例
分享利用 redis 订阅与发布特性,巧妙的现实高性能im系统。为表诚意,先贴源码地址:https://github.com/2881099/im
下载源码后的运行方法:
运行环境:.NETCore 2.1 + redis-server 2.8
下载Redis-x64-2.8.2402.zip,点击 start.bat 运行;或者修改 imServer、web 下面 appsettings.json redis 配置,指向可用的redis-server
cd imServer && dotnet run --urls="http://0.0.0.0:6001"
cd web && dotnet run --urls="http://0.0.0.0:5555"
打开多个浏览器,访问 http://127.0.0.1:5555 发送群消息
1|0
2|0设计思路
终端(如浏览器) 使用 webSocket 连接 imServer;
imServer 根据 clientId 分区管理 webSocket 连接,可群集部署;
webApi 或其他应用端,使用 ImHelper 调用相关方法(如:SendMessage、群聊相关方法),将数据推至 Redis Channel;
imServer 订阅 Redis Channel,收到消息后向终端(如浏览器)推送消息;
1、可缓解并发推送消息过多的问题;
2、可解决连接数过多的问题;
3、解决业务和通讯分离,结构更加清淅;
imServer 充当消息转发,维护连接,代码万年不变不需要重启维护
webApi 负责所有业务
webSocket
如果浏览器使用 webSocket ,iOS 使用其他协议,协议不一致的后果很严重(难维护)。
建议所有端都使用 webSocket 协议,adorid/ios/h5/小程序 全部支持 webSocket 客户端。
业务通讯
IM 系统一般涉及【我的好友】、【我的群】、【历史消息】等等。。
那么,imServer与业务方(webApi)该保持何种关系呢?
用户A向好友B发送消息,分析一下:
- 需要判断B是否为A好友;
- 需要判断A是否有权限;
- 等等。。
诸如此类业务判断会很复杂,如果使用imServer做业务协议,它是不是会变成巨无霸难以维护?
又如获取历史聊天记录,难道客户端要先webSocket.send('gethistory'),再在onmessage里定位回调处理?
发送消息
业务和推送分离的设计,即 imServer 只负责推送工作,webApi 负责业务。
用户A向B发消息:终端A ajax -> webApi -> imServer -> 终端B webSocket.onmessage;
获取历史消息:客户端请求业务方(webApi)接口,返回json(历史消息)。
背后采用 redis 轻量级的订阅发布功能,实现消息缓冲发送,方案必备之一,后期可更换为其他技术。比如 webApi 业务发需要通知1000个人,若不用消息缓冲,会对 webApi 应用程序整体将造成性能损耗。
还有使用 redis 存储一些数据,如在线 clientId,频道信息。
集群分区
单个 imServer 实例支持多少个客户端连接,两千个没问题?如果在线用户有10万人,怎么办???
部署 4 个 imServer:
imServer1 订阅 redisChanne1
imServer2 订阅 redisChanne2
imServer3 订阅 redisChanne3
imServer4 订阅 redisChanne4
业务方(webApi) 根据接收方的 clientId 后四位 16 进制与节点总数取模,定位到对应的 redisChannel,进行 redis->publish 操作将消息定位到相应的 imServer。
每个 imServer 管理着对应的终端连接,当接收到 redis 订阅消息后,向对应的终端连接推送数据。
事件消息
IM 系统比较常用的有上线、下线,在 imServer 层才能准确捕捉事件,但业务代码不合适在这上面编写了。
此时采用 redis 发布订阅技术,将上线、下线等事件向指定频道发布,业务方(webApi) 通过 ImHelper.EventBus 方法进行订阅捕捉。
A向B发文件的例子
1、A向 webapi 传文件
2、webapi 告诉 imServer,A向B正在传文件,ImHelper.SendMessage(B, "A正在给传送文件...")
3、B收到消息,A正在传文件
4、webapi 文件接收完成时告诉imServer,A向B文件传输完毕,ImHelper.SendMessage(B, "A文件传输完毕(含文件链接)")
5、B收到消息,A文件传输完毕(含文件链接)
__EOF__

本文链接:https://www.cnblogs.com/kellynic/p/9286645.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库