前言
上篇的預告好像是“聊天室的小細節,你都注意到了嗎?”。今天也是為那篇做鋪墊吧。之前的版本有好多問題,比如:當前登入使用者是否合法問題,userid引數如果隨便傳後臺沒有驗證。還有一個致命的問題,使用者AB都線上,但是如果A沒有開啟B的視窗或者B沒有開啟A的視窗,那麼發訊息,對方是收不到的。因為他們沒有進入到同一個組裡面。本篇講述了一些Redis的東西。由於專案本身就是為了學習和練習一些東西。所以,Redis並不是我的強項,只不過隨便研究研究,具體專業的用法我也不太會。還在學習中。。。
實現思路
首先,我採用了Redis中的雜湊表結構來儲存使用者的線上資訊。如下圖所示:key代表userid,value是使用者的connectionid。
是不是很簡單,那麼儲存這些資料有什麼好處呢,
1.我們可以統計多少線上使用者
2.配合前端介面,實現某個好友是否線上
3.判斷好友是否線上在決定是否像該好友推送訊息(不線上的話,直接儲存離線訊息就可以)
4.解決前言中存在的問題。對於這個問題詳細解釋一下,比如A給B發訊息,A點選開啟了B的視窗,現在A已經加入到組AB中。但是B不在組AB中,所以,B收不到本組的訊息。假如A開啟B視窗的時候,判斷一下A是否線上,如果A線上,那麼將A加入到AB組中,也就是多了一步 A=》Group的操作。這樣的話,就解決了AB不同組導致收不到訊息的問題。詳細看下圖:
實現細節
我們只要在Hub程式碼中的建立連線,失去連線,重新連線的方法中新增對當前使用者的操作邏輯就可以。
/// <summary> /// 獲取當前使用者資訊 /// </summary> private OnlineUser CurrentOnlineUser { get { return new OnlineUser { connectionid = CurrentConnectId, userid = CurrentUserId }; } } /// <summary> /// 建立連線 /// </summary> /// <returns></returns> public override Task OnConnected() { //將當前使用者新增到redis線上使用者快取中 LayIMCache.Instance.OperateOnlineUser(CurrentOnlineUser); return Clients.Caller.receiveMessage("連線成功"); } /// <summary> /// 失去連線 /// </summary> /// <param name="stopCalled"></param> /// <returns></returns> public override Task OnDisconnected(bool stopCalled) { //將當前使用者從線上使用者列表中剔除 LayIMCache.Instance.OperateOnlineUser(CurrentOnlineUser, isDelete: true); return Clients.Caller.receiveMessage("失去連線"); } /// <summary> /// 重新連線 /// </summary> /// <returns></returns> public override Task OnReconnected() { //將當前使用者新增到redis線上使用者快取中 LayIMCache.Instance.OperateOnlineUser(CurrentOnlineUser); return Clients.Caller.receiveMessage("重新連線"); }
這裡我用的.NET客戶端是 StackExchange.Redis.Extensions.Core ,他其實是在 StackExchange.Redis 的基礎上有一層封裝。用起來更方便一些,喜歡直接用 StackExchange.Redis 的也沒問題。
詳細程式碼如下:
static NewtonsoftSerializer serializer = new NewtonsoftSerializer(); StackExchangeRedisCacheClient cacheClient = new StackExchangeRedisCacheClient(serializer); #region 線上使用者處理 public void OperateOnlineUser(OnlineUser user, bool isDelete = false) { if (isDelete) { cacheClient.HashDelete(LayIMConst.LayIM_All_OnlineUsers, user.userid); } else { cacheClient.HashSetAsync(LayIMConst.LayIM_All_OnlineUsers, user.userid, user.connectionid); } } #endregion
當我們重新整理頁面的時候,會先呼叫 OnDisconnected 方法,在呼叫 OnConnected 方法。不過,HashSet方法如果是同一個key,可以覆蓋其值。
本篇就到這裡了,介面上沒有改動,只不過增加了一些基於redis快取的邏輯。
GitHub:https://github.com/fanpan26/LayIM_NetClient 喜歡的話給一個star吧,謝謝啦。
交流群:145322742