[開源] .NETCore websocket 即時通訊組件---ImCore


ImCore 利用 webSocket 協議實現簡易、高性能、集群即時通訊組件,支持點對點通訊、群聊通訊、上線下線事件消息等眾多實用性功能。

Quick Start

dotnet add package ImCore

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),偽代碼:

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.8

下載Redis-x64-2.8.2402.zip,點擊 start.bat 運行;

cd imServer && dotnet run

cd web && dotnet run

打開多個瀏覽器,訪問 http://127.0.0.1:5000 發送群消息

image

設計思路

終端(如瀏覽器) 使用 webSocket 連接 imServer;

imServer 根據 clientId 分區管理 webSocket 連接,可群集部署;

webApi 或其他應用端,使用 ImHelper 調用相關方法(如:SendMessage、群聊相關方法),將數據推至 Redis Channel;

imServer 訂閱 Redis Channel,收到消息后向終端(如瀏覽器)推送消息;

1、可緩解並發推送消息過多的問題;

2、可解決連接數過多的問題;

3、解決業務和通訊分離,結構更加清淅;

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發文件的例子

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文件傳輸完畢(含文件鏈接)

有感而發

為什么說 signalr 不合適做 im?

im 的特點必定是長連接,輪訓的功能用不上。

因為他是雙工通訊的設計,用 hub.invoke 發送命令給服務端處理業務,其他就和 ajax 差不多,用來代替 ajax 減少 http 請求數量比較看好。

但是過多使用 hub,signalr 服務端會被業務入侵嚴重,業務變化頻繁后不得不重新發布版本,每次部署所有終端都會斷開連接,遇到5分鍾發一次業務補丁的時候,類似離線和上線提示好友的功能就無法實現。

ImCore 的設計是業務和推送分離,即 imServer 永不更新重啟,業務全部在 webApi 上編寫,終端連接的是 imServer 就不會頻繁重啟的問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM