基於 websocket 實現的 im 實時通訊案例


分享利用 redis 訂閱與發布特性,巧妙的現實高性能im系統。為表誠意,先貼源碼地址:https://github.com/2881099/im

下載源碼后的運行方法:

運行環境:.NETCore 2.1 + redis-server 2.8

下載Redis-x64-2.8.2402.zip,點擊 start.bat 運行;或者修改 imServer、web 下面 appsettings.json redis 配置,指向可用的redis-server

cd imServer && dotnet run --urls="http://0.0.0.0:6001"

cd web && dotnet run --urls="http://0.0.0.0:5555"

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

設計思路

終端(如瀏覽器) 使用 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文件傳輸完畢(含文件鏈接)


免責聲明!

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



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