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