ImCore 利用 webSocket 協議實現簡易、高性能、集羣即時通信組件,支持點對點通信、羣聊通信、上線下線事件消息等衆多實用性功能。javascript
dotnet add package ImCorehtml
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服務端前端
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, 頻道名, 消息內容) | 發送消息,全部在線的用戶將收到消息 |
前端鏈接 webSocket 前,應該先請求 webApi 得到受權過的地址(ImHelper.PrevConnectServer),僞代碼:html5
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) { //... }; })
運行環境:.NETCore 2.1 + redis-server 2.8java
下載Redis-x64-2.8.2402.zip,點擊 start.bat 運行;ios
cd imServer && dotnet runweb
cd web && dotnet runajax
打開多個瀏覽器,訪問 http://127.0.0.1:5000 發送羣消息redis
終端(如瀏覽器) 使用 webSocket 鏈接 imServer;json
imServer 根據 clientId 分區管理 webSocket 鏈接,可羣集部署;
webApi 或其餘應用端,使用 ImHelper 調用相關方法(如:SendMessage、羣聊相關方法),將數據推至 Redis Channel;
imServer 訂閱 Redis Channel,收到消息後向終端(如瀏覽器)推送消息;
一、可緩解併發推送消息過多的問題;
二、可解決鏈接數過多的問題;
三、解決業務和通信分離,結構更加清淅;
imServer 充當消息轉發,維護鏈接,代碼萬年不變不須要重啓維護
webApi 負責全部業務
若是瀏覽器使用 webSocket ,iOS 使用其餘協議,協議不一致的後果很嚴重(難維護)。
建議全部端都使用 webSocket 協議,adorid/ios/h5/小程序 所有支持 webSocket 客戶端。
IM 系統通常涉及【個人好友】、【個人羣】、【歷史消息】等等。。
那麼,imServer與業務方(webApi)該保持何種關係呢?
用戶A向好友B發送消息,分析一下:
諸如此類業務判斷會很複雜,若是使用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 方法進行訂閱捕捉。
一、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 就不會頻繁重啓的問題。