ASP.NET SingalR 點對點聊天實現思路總結


前一段時間寫了一個簡單的聊天室,是群聊的方式。博客地址:http://www.cnblogs.com/panzi/p/4980346.html。還有一種需求就是常見的尤其是培訓機構的主頁面,經常會有1對1咨詢聊天窗口。那么用singalR如何實現1對1聊天呢。

 

其實很簡單。我們先看看SingalR里的IHubConnectionContext接口代碼:

public interface IHubConnectionContext<T>
    {
     //所有連接服務器的用戶 T All {
get; }      //除了一部分用戶 T AllExcept(params string[] excludeConnectionIds);
//這個就是我們要用的點對點,針對單個用戶發送消息 T Client(
string connectionId);
//群發消息 T Clients(IList
<string> connectionIds);
//按組群發消息 T Group(
string groupName, params string[] excludeConnectionIds);
//多組群發消息 T Groups(IList
<string> groupNames, params string[] excludeConnectionIds);
//用戶 T User(
string userId); T Users(IList<string> userIds); }

 

這里我們就用  T Client(string connectionId); 這個方法。調用方式為 Clients.Client("connectionId").clientFun(msg); //(clientFun為自定義客戶端接收消息方法名)具體細節不在描述,這里比較關鍵的就是,如何知道對方的ConnectionId,因為ConnectionId是自動生成的而且,每次刷新頁面都會變,SingalR本身又不帶統計在線用戶的方法,所以,這個需要自己去實現。思路很清晰,這里先用 靜態List做用戶在線列表信息存儲。代碼如下:

 /// <summary>
    /// 簡單用戶統計model 
    /// </summary>
    public class HubUser
    {
        /// <summary>
        /// 連接服務器之后,自動生成的connectionId
        /// </summary>
        public string ConnectionId { get; set; }
        /// <summary>
        /// 客戶端用戶的主鍵ID
        /// 一般和業務相關的用戶ID
        /// </summary>
        public string ClientUserId { get; set; }
        /// <summary>
        /// 聊天所在組
        /// </summary>
        public string GroupId { get; set; }
    }
 public sealed class OnlineUserPool
    {
        private static Lazy<List<HubUser>> _onlineUser = new Lazy<List<HubUser>>();
        public static List<HubUser> OnlineUser { get { return _onlineUser.Value; } }

        /// <summary>
        /// 添加用戶,一般在用戶 連接服務器或者用戶重新連接的時候
        /// </summary>
        /// <param name="user"></param>
        public static void AddUser(HubUser user)
        {
            DeleteUser(user);
            _onlineUser.Value.Add(user);
        }
        /// <summary>
        /// 刪除某個在線用戶
        /// </summary>
        /// <param name="clientUserId"></param>
        /// <param name="connectionId"></param>
        public static void DeleteUser(HubUser user, bool unConnected = true)
        {
            var onlineUser = IsOnline(user);
            if (onlineUser != null)
            {
                _onlineUser.Value.Remove(onlineUser);
            }
        }
        public static HubUser IsOnline(HubUser user)
        {
            if (user == null) { throw new ArgumentNullException(); }
            string clientUserId = user.ClientUserId;
            string connectionId = user.ConnectionId;
            if (!string.IsNullOrEmpty(clientUserId))
            {
                return _onlineUser.Value.FirstOrDefault(x => x.ClientUserId == clientUserId);
            }
            else
            {
                return _onlineUser.Value.FirstOrDefault(x => x.ConnectionId == connectionId);
            }
        }
        /// <summary>
        /// 獲取在線總數
        /// </summary>
        /// <returns></returns>
        public static long GetUserCount()
        {
            return _onlineUser.Value.Count;
        }
    }

可以看到 OnlineUserPool 類實現了往靜態列表添加用戶,刪除用戶等一系列操作。

添加用戶操作需要,在用戶接入到聊天室的時候執行:

  public Task Join(ZjMessage message)
        {
            message.connectionId = Context.ConnectionId;
            //就是用戶加入的時候
            OnlineUserPool.AddUser(new HubUser
            {
                ClientUserId = message.userid,
                ConnectionId = Context.ConnectionId
            });
            message.msg = "當前已經有:" + OnlineUserPool.GetUserCount() + " 人在線";
            return Clients.All.receiveMessage(new { type = "join", msg = message });
        }

刪除用戶操作就在重寫OnDisconnect方法里執行,需要根據ConnectionId刪除

 public override Task OnDisconnected(bool stopCalled)
        {
            ZjMessage message = new ZjMessage(Context.ConnectionId);
            //用戶離開
            //用戶斷線,需要將該用戶從列表中刪除,(應該考慮短暫失去連接的可能性,不能直接從列表刪除。)
            OnlineUserPool.DeleteUser(new HubUser
            {
                ConnectionId = Context.ConnectionId
            });
            return Clients.All.receiveMessage(new { type = "left", msg = message });
        }

所以,當你想點對點發送消息的時候,將對方userId傳送到服務器,然后服務器從在線列表里面查詢出相應的connectionID,然后將消息推送到該connectionID的用戶,就實現了在線兩個人聊天了。當然,用靜態列表的方式也不是很好,如果用戶量龐大,會不會出什么問題呢,我具體沒研究過。一般的方案,是放在專門的緩存服務器存儲,或者NOSQL數據庫存儲也可以吧,方案有很多,由於沒有具體做過也不敢多費口舌。這個思路是沒問題的,當然也會有更好的方法吧。


免責聲明!

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



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