使用 websocket 协议实现简易、高性能(单机支持5万+连接)、集群即时通讯组件,支持点对点通讯、群聊通讯、上线下线事件消息等众多实用性功能
使用场景:好友聊天、群聊天、直播间、实时评论区、游戏。
ImServer 服务端
- public void Configure(IApplicationBuilder app)
- {
- app.UseFreeImServer(new ImServerOptions
- {
- Redis = new FreeRedis.RedisClient("127.0.0.1:6379,poolsize=5"),
- Servers = new[] { "127.0.0.1:6001" }, //集群配置
- Server = "127.0.0.1:6001"
- });
- }
复制代码 一套永远不需要迭代更新的 ImServer 服务端,支持 .NET6.0、.NETCore2.1+、NETStandard2.0
WebApi 业务端
- public void Configure(IApplicationBuilder app)
- {
- //...
- ImHelper.Initialization(new ImClientOptions
- {
- Redis = new FreeRedis.RedisClient("127.0.0.1:6379,poolsize=5"),
- Servers = new[] { "127.0.0.1:6001" }
- });
- ImHelper.EventBus(
- t => Console.WriteLine(t.clientId + "上线了"),
- t => Console.WriteLine(t.clientId + "下线了"));
- }
复制代码 [td]ImHelper方法 | 参数 | 描述 | PrevConnectServer | (clientId, string) | 在终端准备连接 websocket 前调用 | SendMessage | (发送者, 接收者, 消息内容, 是否回执) | 发送消息 | GetClientListByOnline | - | 返回所有在线clientId | HasOnline | clientId | 判断客户端是否在线 | EventBus | (上线委托, 离线委托) | socket上线与下线事件 | [td]频道 | 参数 | 描述 | JoinChan | (clientId, 频道名) | 加入 | LeaveChan | (clientId, 频道名) | 离开 | GetChanClientList | (频道名) | 获取频道所有clientId | GetChanList | - | 获取所有频道和在线人数 | GetChanListByClientId | (clientId) | 获取用户参与的所有频道 | GetChanOnline | (频道名) | 获取频道的在线人数 | SendChanMessage | (clientId, 频道名, 消息内容) | 发送消息,所有在线的用户将收到消息 |
- clientId 应该与用户id相同,或者关联;
- 频道适用临时的群聊需求,如聊天室、讨论区;
ImHelper 支持 .NetFramework 4.5+、.NetStandard 2.0 Html5 终端终端连接 websocket 前,应该先请求 WebApi 获得授权过的地址(ImHelper.PrevConnectServer),伪代码: - ajax('/prev-connect-imserver', function(data) {
- var url = data; //此时的值:ws://127.0.0.1:6001/ws?token=xxxxx
- var sock = new WebSocket(url);
- sock.onmessage = function (e) {
- //...
- };
- })
复制代码运行环境:.NET6.0 + redis-server 2.8+ 打开多个浏览器,分别访问 http://127.0.0.1:5000 发送群消息
使用 websocket 协议实现简易、高性能(单机支持5万+连接)、集群即时通讯组件,支持点对点通讯、群聊通讯 ...
分析痛点协议痛点:如果浏览器使用 websocket 协议,iOS 使用其他协议,协议不一致将很难维护。 职责痛点:IM 的系统一般涉及【我的好友】、【我的群】、【历史消息】等等。。 ImServer 与 WebApi(业务方) 该保持何种关系呢? 用户A向好友B发送消息,分析一下: 获取历史聊天记录,多个 终端 websocket.send('gethistory'),再在 onmessage 定位回调处理,多麻烦啊? 诸如此类业务判断会很复杂,使用 ImServer 做业务逻辑,最终 ImServer 和 终端 都将变成巨无霸难以维护。 设计思路终端(如浏览器/小程序/iOS/android) 统一使用 websocket 连接 ImServer; ImServer(支持集群)根据 clientId 分区管理 websocket 连接; WebApi 使用 ImHelper 调用方法(如:SendMessage、群聊相关方法),将数据推至 Redis chan; ImServer 订阅 Redis chan,收到消息后向 终端 推送消息; - 缓解了并发推送消息过多的问题;
- 解决了连接数过多的问题;
- 解耦了业务和通讯,架构更加清淅;
- ImServer 充当消息转发,连接维护,代码万年不变、且不需要重启维护
- WebApi 负责所有业务
举例1、用户A向B发送消息:终端A ajax -> WebApi -> ImServer -> 终端B websocket.onmessage; 举例2、获取历史聊天记录:终端 请求 WebApi(业务方) 接口,返回json(历史消息)。 举例3、A向B发文件的例子: - A向 WebApi 传文件
- WebApi 通知 ImServer,ImHelper.SendMessage(B, "A正在给传送文件...")
- B收到消息,A正在给传送文件...
- WebApi 文件接收完成时通知 ImServer,ImHelper.SendMessage(B, "A文件传输完毕(含文件链接)")
- B收到消息,A文件传输完毕(含文件链接)
FreeIM 强依赖 redis-server 组件功能: - 集成了 redis 轻量级的订阅发布功能,实现消息缓冲发送,后期可更换为其他技术
- 使用了 redis 存储一些关系数据,如在线 clientId、频道信息、授权信息等
集群分区单个 ImServer 实例支持多少个客户端连接,3万?如果在线用户有10万人,怎么办??? 部署 4 个 ImServer: - ImServer1 订阅 redisChan1
- ImServer2 订阅 redisChan2
- ImServer3 订阅 redisChan3
- ImServer4 订阅 redisChan4
WebApi(业务方) 根据接收方的 clientId 后四位 16 进制与节点总数取模,定位到对应的 redisChan,进行 redis->publish 操作将消息定位到相应的 ImServer。 每个 ImServer 管理着对应的终端连接,当接收到 redis 订阅消息后,向对应的终端连接推送数据。 事件消息IM 系统比较常用的有上线、下线,在 ImServer 层才能准确捕捉事件,但业务代码不合适在这上面编写了。 此时采用 redis 发布订阅,将上线、下线等事件向指定频道发布,WebApi(业务方) 通过 ImHelper.EventBus 方法进行订阅捕捉。
使用 websocket 协议实现简易、高性能(单机支持5万+连接)、集群即时通讯组件,支持点对点通讯、群聊通讯 ...
提取码下载:
|