zoukankan      html  css  js  c++  java
  • Asp.NET MVC 之心跳/长连接

    0x01 在线用户类,我的用户唯一性由ID和类型识别(因为在不同的表里)

    public class UserIdentity : IEqualityComparer<UserIdentity>
        {
            internal UserIdentity() { }
            public UserIdentity(int userId, int userType)
            {
                this.UserID = userId;
                this.UserType = userType;
            }
            public int UserID { get; private set; }
            public int UserType { get; private set; }
    
            public bool Equals(UserIdentity x, UserIdentity y)
            {
                return x.UserID == y.UserID && x.UserType == y.UserType;
            }
    
            public int GetHashCode(UserIdentity obj)
            {
                return obj.UserID * (obj.UserType + 10);
            }
        }
        public class AliveUser
        {
            private AliveUser() { }
            public AliveUser(string sessionID, int userID, int userType)
            {
                this.SessionID = sessionID;
                this.StartAt = DateTime.Now;
                this.User = new UserIdentity(userID, userType);
            }
    
            public void SetExpires(DateTime expires)
            {
                this.Expires = expires;
            }
            public string SessionID { get; private set; }
            public DateTime StartAt { get; private set; }
            public DateTime Expires { get; private set; }
            public UserIdentity User { get; private set; }
        }

    0x02 会话管理,线程+字典

    public class AliveSessionHelper
        {
            static AliveSessionHelper()
            {
                thread.IsBackground = true;
                thread.Start();
            }
            public static int TimeoutInMinutes = 1;
            private static object syncObject = new object();
            public static Dictionary<string, AliveUser> OnlineUsers = new Dictionary<string, AliveUser>();
            public static Dictionary<UserIdentity, List<AliveUser>> GetOnlineUsers()
            {
                lock (syncObject)
                {
                    var list = OnlineUsers.Values.ToList();
                    var grouping = list.GroupBy(x => x.User,new UserIdentity());
                    var dict = new Dictionary<UserIdentity, List<AliveUser>>(grouping.Count());
                    foreach (var item in grouping)
                    {
                        dict.Add(item.Key, item.ToList());
                    }
                    return dict;
                }
            }
    
            public static void AddAliveUser(string sessionID, int userID, int userType)
            {
                AddAliveUser(new AliveUser(sessionID, userID, userType));
            }
    
            public static void AddAliveUser(AliveUser user)
            {
    
                lock (syncObject)
                {
                    var aliveUser = OnlineUsers.ContainsKey(user.SessionID) ? OnlineUsers[user.SessionID] : null;
                    if (aliveUser == null)
                    {
                        OnlineUsers.Add(user.SessionID, user);
                    }
    
                    var expires = DateTime.Now.AddMinutes(TimeoutInMinutes);
                    OnlineUsers[user.SessionID].SetExpires(expires);
                }
            }
    
            private static Thread thread = new Thread(ThreadStartBody);
            private static void ThreadStartBody()
            {
                while (true)
                {
                    lock (syncObject)
                    {
                        var delList = new List<Guid>();
                        var list = OnlineUsers.Values.ToList();
                        foreach (var item in list)
                        {
                            if (item.Expires.Subtract(DateTime.Now).TotalSeconds < 5)
                            {
                                OnlineUsers.Remove(item.SessionID);
                            }
                        }
                    }
                    Thread.Sleep(29);
                }
            }
        }

    0x03 控制器实现

    [SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
        [Authorize]
        public class ApiController : AsyncController
        {
            public async Task<ActionResult> KeepAlive()
            {
                if (!User.Identity.IsAuthenticated) {
                    return null;
                }
                AliveSessionHelper.AddAliveUser(Session.SessionID, AdminUserService.Instance.CurrentUserID, 0);
                return await Task.Delay(TimeSpan.FromSeconds(30)).ContinueWith(task =>
                {
                    return JavaScript("$.getScript('/admin/api/keepalive');");
                });
            }
        }   

    注意

    1、[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]是必须的,否则刷新(重复调用)会锁死,原理熟手自己领会,新手照做即可。

    2、/admin/api/keepalive 调用的Action是自身。

    3、服务端控制请求的释放间隔。这里设置的30s。如果要更长时间,如超过1分钟可能导致Action超时异常,需要加AsyncTimeoutAttribute特性设置Action超时时间大于释放间隔。

    0x04 前端代码,需要jQuery。就是触发首次调用,然后就靠服务端返回js自动执行。

    $(function () {
             //KeepAlive
             $.getScript('/admin/api/keepalive');
    }

    是不是感觉代码很简单?注重简单实用好用是博主一贯的追求。

    拷贝请注明来源博客园,道木先生。.Net软件交流群283590657

      

  • 相关阅读:
    【PHPStorm使用手册】如何设置字体大小?
    Django——admin组件简单入门
    cookie与session
    Django
    练习题
    线程理论之大白话
    队列
    初识gevent模块
    Python第三方模块安装
    Python标准模块_concurrent.futures
  • 原文地址:https://www.cnblogs.com/mrtiny/p/5170286.html
Copyright © 2011-2022 走看看