[開源] .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

相關文章
相關標籤/搜索