ASP.NET SignalR 與 LayIM2.0 配合輕鬆實現Web聊天室(八) 之 用 Redis 實現使用者線上離線狀態訊息處理

丶Pz發表於2016-08-29

前言

  上篇的預告好像是“聊天室的小細節,你都注意到了嗎?”。今天也是為那篇做鋪墊吧。之前的版本有好多問題,比如:當前登入使用者是否合法問題,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

相關文章