1. 程式人生 > >[開源] .NETCore websocket 即時通訊元件---ImCore

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

前言

ImCore 是一款 .NETCore 下利用 WebSocket 實現的簡易、高效能、叢集即時通訊元件,支援點對點通訊、群聊通訊、上線下線事件訊息等眾多實用性功能。

開源地址:https://github.com/2881099/im ,求 star~~

快速開始

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)。

執行示例

執行環境:.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 傳送群訊息

設計思路

imServer 是 websocket 服務中心,可部署多例項,按clientId分割槽管理socket連線;

webApi 或其他應用端,使用 ImHelper 呼叫相關方法(如:SendMessage、群聊相關方法);

訊息傳送利用了 redis 訂閱釋出技術。每個 imServer 訂閱相應的頻道,收到訊息,指派 websocket 向終端(如瀏覽器)傳送訊息;

1、可緩解併發推送訊息過多的問題;

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

客戶端連線流程:client -> websocket -> imserver

imserver 訂閱訊息:client <- imserver <- redis channel

推送訊息流程:web1 -> sendmsg方法 -> redis channel -> imserver

imserver 充當訊息轉發,及維護連線中心,程式碼萬年不變不需要重啟維護;

WebSocket

比較笨的辦法是瀏覽器端使用websocket,其他端socket,這種混亂的設計非常難維護。

強烈建議所有端都使用websocket協議,adorid/ios/h5/小程式全部支援websocket客戶端。

業務與通訊協議

im系統一般涉及【我的好友】、【我的群】、【歷史訊息】等等。。

那麼,imServer與業務方(webApi)該保持何種關係呢?

使用者A向好友B傳送訊息,分析一下:

  • 需要判斷B是否為A好友;
  • 需要判斷A是否有許可權;
  • 等等。。

諸如此類業務判斷會很複雜,我們試想一下,如果使用imServer做業務協議,它是不是會變成巨無霸難以維護?

又比如獲取歷史聊天記錄,難道客戶端要先websocket.send('gethistory'),再在onmessage裡定位回撥處理?


我們可以這樣設定,所有使用者的主動行為走業務方(webApi),imServer只負責即時訊息推送。什麼意思?

使用者A向好友B傳送訊息:客戶端請求業務方(webApi)介面,由業務方(webApi)後端向imServer發起推送請求,imServer收到指令後,向前端使用者B的websocket傳送資料,使用者B收到了訊息。

獲取歷史訊息:客戶端請求業務方(webApi)介面,返回json(歷史訊息)

回執:使用者A如何知道訊息傳送狀態(成功或失敗或不線上)?imServer端向用戶B傳送訊息時,把狀態以訊息的方式推給使用者A即可(按上面的邏輯),具體請看原始碼吧。。。

傳送訊息

採用 redis 輕量級的訂閱釋出功能,實現訊息緩衝傳送。

叢集分割槽

單個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 方法進行訂閱捕捉。

結束語

謝謝支援