基于 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 负责所有业务

1|0webSocket

如果浏览器使用 webSocket ,iOS 使用其他协议,协议不一致的后果很严重(难维护)。

建议所有端都使用 webSocket 协议,adorid/ios/h5/小程序 全部支持 webSocket 客户端。

1|0业务通讯

IM 系统一般涉及【我的好友】、【我的群】、【历史消息】等等。。

那么,imServer与业务方(webApi)该保持何种关系呢?

用户A向好友B发送消息,分析一下:

  • 需要判断B是否为A好友;
  • 需要判断A是否有权限;
  • 等等。。

诸如此类业务判断会很复杂,如果使用imServer做业务协议,它是不是会变成巨无霸难以维护?

又如获取历史聊天记录,难道客户端要先webSocket.send('gethistory'),再在onmessage里定位回调处理?

1|0发送消息

业务和推送分离的设计,即 imServer 只负责推送工作,webApi 负责业务。

用户A向B发消息:终端A ajax -> webApi -> imServer -> 终端B webSocket.onmessage;

获取历史消息:客户端请求业务方(webApi)接口,返回json(历史消息)。

背后采用 redis 轻量级的订阅发布功能,实现消息缓冲发送,方案必备之一,后期可更换为其他技术。比如 webApi 业务发需要通知1000个人,若不用消息缓冲,会对 webApi 应用程序整体将造成性能损耗。

还有使用 redis 存储一些数据,如在线 clientId,频道信息。

1|0集群分区

单个 imServer 实例支持多少个客户端连接,两千个没问题?如果在线用户有10万人,怎么办???

部署 4 个 imServer:

imServer1 订阅 redisChanne1

imServer2 订阅 redisChanne2

imServer3 订阅 redisChanne3

imServer4 订阅 redisChanne4

业务方(webApi) 根据接收方的 clientId 后四位 16 进制与节点总数取模,定位到对应的 redisChannel,进行 redis->publish 操作将消息定位到相应的 imServer。

每个 imServer 管理着对应的终端连接,当接收到 redis 订阅消息后,向对应的终端连接推送数据。

1|0事件消息

IM 系统比较常用的有上线、下线,在 imServer 层才能准确捕捉事件,但业务代码不合适在这上面编写了。

此时采用 redis 发布订阅技术,将上线、下线等事件向指定频道发布,业务方(webApi) 通过 ImHelper.EventBus 方法进行订阅捕捉。

image

1|0A向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__

本文作者FreeSql & CSRedis
本文链接https://www.cnblogs.com/kellynic/p/9286645.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   nicye  阅读(7850)  评论(3编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示