ImCore 利用 webSocket 协议实现简易、高性能、集群即时通信组件,支持点对点通信、群聊通信、上线下线事件消息等众多实用性功能。javascript
dotnet add package ImCorehtml
public void Configure(IApplicationBuilder app) { app.UseimServer(new imServerOptions { Redis = new CSRedis.CSRedisClient("127.0.0.1:6379,poolsize=5"), Servers = new[] { "127.0.0.1:6001" }, //集群配置 Server = "127.0.0.1:6001" }); }
一套永远不须要迭代更新的IM服务端前端
public void Configure(IApplicationBuilder app) { //... ImHelper.Initialization(new ImClientOptions { Redis = new CSRedis.CSRedisClient("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 + "下线了")); }
ImHelper方法 | 参数 | 描述 |
---|---|---|
PrevConnectServer | (clientId, string) | 在终端准备链接 webSocket 前调用 |
SendMessage | (发送者, 接收者, 消息内容, 是否回执) | 发送消息 |
GetClientListByOnline | - | 返回全部在线clientId |
EventBus | (上线委托, 离线委托) | socket上线与下线事件 |
频道 | 参数 | 描述 |
---|---|---|
JoinChan | (clientId, 频道名) | 加入 |
LeaveChan | (clientId, 频道名) | 离开 |
GetChanClientList | (频道名) | 获取频道全部clientId |
GetChanList | - | 获取全部频道和在线人数 |
GetChanListByClientId | (clientId) | 获取用户参与的全部频道 |
GetChanOnline | (频道名) | 获取频道的在线人数 |
SendChanMessage | (clientId, 频道名, 消息内容) | 发送消息,全部在线的用户将收到消息 |
前端链接 webSocket 前,应该先请求 webApi 得到受权过的地址(ImHelper.PrevConnectServer),伪代码:java
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) { //... }; })
运行环境:.NETCore 2.1 + redis-server 2.8ios
下载Redis-x64-2.8.2402.zip,点击 start.bat 运行;web
cd imServer && dotnet runajax
cd web && dotnet runredis
打开多个浏览器,访问 http://127.0.0.1:5000 发送群消息json
终端(如浏览器) 使用 webSocket 链接 imServer;小程序
imServer 根据 clientId 分区管理 webSocket 链接,可群集部署;
webApi 或其余应用端,使用 ImHelper 调用相关方法(如:SendMessage、群聊相关方法),将数据推至 Redis Channel;
imServer 订阅 Redis Channel,收到消息后向终端(如浏览器)推送消息;
一、可缓解并发推送消息过多的问题;
二、可解决链接数过多的问题;
三、解决业务和通信分离,结构更加清淅;
imServer 充当消息转发,维护链接,代码万年不变不须要重启维护
webApi 负责全部业务
若是浏览器使用 webSocket ,iOS 使用其余协议,协议不一致的后果很严重(难维护)。
建议全部端都使用 webSocket 协议,adorid/ios/h5/小程序 所有支持 webSocket 客户端。
IM 系统通常涉及【个人好友】、【个人群】、【历史消息】等等。。
那么,imServer与业务方(webApi)该保持何种关系呢?
用户A向好友B发送消息,分析一下:
诸如此类业务判断会很复杂,若是使用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向 webapi 传文件
二、webapi 告诉 imServer,A向B正在传文件,ImHelper.SendMessage(B, "A正在给传送文件...")
三、B收到消息,A正在传文件
四、webapi 文件接收完成时告诉imServer,A向B文件传输完毕,ImHelper.SendMessage(B, "A文件传输完毕(含文件连接)")
五、B收到消息,A文件传输完毕(含文件连接)
为何说 signalr 不合适作 im?
im 的特色一定是长链接,轮训的功能用不上。
由于他是双工通信的设计,用 hub.invoke 发送命令给服务端处理业务,其余就和 ajax 差很少,用来代替 ajax 减小 http 请求数量比较看好。
可是过多使用 hub,signalr 服务端会被业务入侵严重,业务变化频繁后不得不从新发布版本,每次部署全部终端都会断开链接,遇到5分钟发一次业务补丁的时候,相似离线和上线提示好友的功能就没法实现。
ImCore 的设计是业务和推送分离,即 imServer 永不更新重启,业务所有在 webApi 上编写,终端链接的是 imServer 就不会频繁重启的问题。
原文出处:https://www.cnblogs.com/kellynic/p/11273742.html