[开源] .NETCore websocket 即时通信组件---ImCore

ImCore 利用 webSocket 协议实现简易、高性能、集群即时通信组件,支持点对点通信、群聊通信、上线下线事件消息等众多实用性功能。javascript

Quick Start

dotnet add package ImCorehtml

IM服务端

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服务端前端

WebApi业务端

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, 频道名, 消息内容) 发送消息,全部在线的用户将收到消息
  • clientId 应该与 webApi 的用户id相同,或者有关联;
  • 频道适用临时的群聊需求,如:聊天室、即时讨论区;

Html5终端

前端链接 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) {
        //...
    };
})

Demo

运行环境:.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

image

设计思路

终端(如浏览器) 使用 webSocket 链接 imServer;小程序

imServer 根据 clientId 分区管理 webSocket 链接,可群集部署;

webApi 或其余应用端,使用 ImHelper 调用相关方法(如:SendMessage、群聊相关方法),将数据推至 Redis Channel;

imServer 订阅 Redis Channel,收到消息后向终端(如浏览器)推送消息;

一、可缓解并发推送消息过多的问题;

二、可解决链接数过多的问题;

三、解决业务和通信分离,结构更加清淅;

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 方法进行订阅捕捉。

image

A向B发文件的例子

一、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

相关文章
相关标签/搜索