大家好,有些BBS里面统计在线数据的时候能显示出每个用户目前所在的版块。他们是怎么做的啊?

解决方案 »

  1.   


    就是论坛里面统计在线情况比如说用户A登录了一个BBS,进入了“.NET”版块,在BBS的上面可以知道用户A当前在哪个版块,显示出来。
    就像某些游戏里面的“好友跟踪”一样。可以知道好友现在在哪里?如:在线情况:
             A   当前正在“.NET”版块;
             B   当前正在“***”版块;
      

  2.   

    socket是监听.....我不知道5楼想用监听做什么?心跳包是用来检测对方是否掉线的,用来检测他在哪个页面,是不是有点浪费资源?还是想在服务器端知道他在什么板块?如果你只是想客户端显示,直接用request来获取form信息么,这不是简单么
      

  3.   

    web程序是无状态的,只能等Session过期
    Session退出时实现人数统计不准确。非法关机或关闭IE不会执行  
    要记录用户日志和操作时间,再用定时器刷新计算用户  
    已经有固定时间没有活动的用户,然后删除  
      

  4.   


    不是Session过期的问题。
    http://www.diaoyuweng.com/member.php?action=online
    就是上面那个页面。它能统计出
    用户名 时间 当前动作 所在版块 所在主题 
    游客  14:13  浏览帖子  安徽钓鱼网  我是才加入的合肥钓友,请大家多加关照 ...  
    游客  14:13  浏览帖子  鱼获战报(垂钓日记)  好久没发贴了,昨天拉一条鲤鱼!  
    游客  14:13  浏览帖子  湖北钓鱼网  湖北渔塘(场)资料整理贴(2008-2009 ...  
    不会是每进入一个连接都记录一次然后显示出来的吧。
      

  5.   


    随着网站访问量的增加,在线用户实体信息的存储方式变得重要起来。存储在线用户的信息一般有这三种方案:     1、用户的实体信息保存在Session里,简单方便,随着Session的过期用户信息自动过期。     2、用户信息保存在数据库中,用一个表存储在线的用户信息。     3、用户信息保存在内存。     当前项目用的是第一种方法,把用户的实体信息保存在Session中,虽然使用方便,但总感觉很别扭。Discuz!NT使用的是第二种方法,把在线用户标识保存在一个表中,从cookie跟读取用户的ID,并从用户信息表查询该用户的信息,组装到实体中。如果有大量的用户在线同时操作时,这也不是一个很好的解决办法。     这里选择第三种解决方案,把用户信息保存到内存。     我们使用Dictionary来存储用户信息,由于Dictionary不是线程安全的,因此需要注意只能单线程更新字典。     先定义一个保存用户信息的实体: internal class UserEntity<T>
    {
        /// <summary>
        /// 用户信息
        /// </summary>
        internal T UserInfo { get; set; }    /// <summary>
        /// 添加到列表的时间戳
        /// </summary>
        internal DateTime Timestamp { get; set; }
    }     使用泛型包装用户实体,并增加一个时间戳,表示该用户信息添加到内存的时间,过期是根据这个时间来判断的。     再增加一个在线用户信息管理类: /// <summary>
    /// 在线用户缓存管理
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class UserCacheManager<T>
    {
        #region 静态属性
        /// <summary>
        /// 静态用户缓存表
        /// </summary>
        private static Dictionary<long, UserEntity<T>> _UserList = new Dictionary<long, UserEntity<T>>();
        /// <summary>
        /// 过期时间
        /// </summary>
        private static int _ExpiredMinutes = 30;
        /// <summary>
        /// 定时器
        /// </summary>
        private static Timer _Timer = null;
        #endregion    #region 静态构造函数
        /// <summary>
        /// 静态构造函数
        /// 初始化计时器
        /// </summary>
        static UserCacheManager()
        {
            _Timer = new Timer(new TimerCallback(TimerClear), null, 60000, _ExpiredMinutes * 60000);
        }
        #endregion    #region 私有方法
        /// <summary>
        /// 清除在线用户
        /// </summary>
        /// <param name="sender"></param>
        private static void TimerClear(object sender)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncClear));
        }    /// <summary>
        /// 异步清除过期的在线用户
        /// </summary>
        /// <param name="sender"></param>
        private static void AsyncClear(object sender)
        {
            //当前时间
            DateTime timestamp = DateTime.Now.AddMinutes(0 - _ExpiredMinutes);
            //过期的用户列表
            var expiredUserList =
                (from userEntity in _UserList where userEntity.Value.Timestamp <= timestamp select userEntity);
            if (expiredUserList != null && expiredUserList.Count() > 0)
            {
                List<long> expiredUserIdentities = expiredUserList.Select(o => o.Key).ToList();
                lock (_UserList)
                {
                    foreach (long userId in expiredUserIdentities)
                        _UserList.Remove(userId);
                }
            }
        }
        #endregion    #region 公共方法
        /// <summary>
        /// 增加在线用户
        /// </summary>
        /// <param name="userIdentity">用户身份标识</param>
        /// <param name="userInfo">用户实体</param>
        public static void Add(long userIdentity, T userInfo)
        {
            lock (_UserList)
            {
                #region 创建用户实体
                UserEntity<T> userEntity = new UserEntity<T>
                {
                    Timestamp = DateTime.Now,
                    UserInfo = userInfo
                };
                #endregion            if (_UserList.Keys.Contains(userIdentity))
                {
                    _UserList[userIdentity] = userEntity;
                }
                else
                {
                    _UserList.Add(userIdentity, userEntity);
                }
            }
        }    /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <param name="userIdentity"></param>
        /// <returns></returns>
        public static T Get(long userIdentity)
        {
            lock (_UserList)
            {
                if (_UserList.Keys.Contains(userIdentity))
                {
                    _UserList[userIdentity].Timestamp = DateTime.Now;
                    return _UserList[userIdentity].UserInfo;
                }
                else
                {
                    return default(T);
                }
            }
        }    /// <summary>
        /// 移除用户缓存信息
        /// </summary>
        /// <param name="userIdentity"></param>
        public static void Remove(long userIdentity)
        {
            if (_UserList.Keys.Contains(userIdentity))
            {
                lock (_UserList)
                {
                    _UserList[userIdentity].Timestamp = DateTime.Now.AddDays(-1);
                }
            }
        }
        #endregion
    }     Dictionary<long, UserEntity<T>> _UserList用来保存在线的用户列表。     在静态构造函数中声明了一个定时器,定时器负责清理过期的用户信息。并把清理用户信息的方法装入线程池执行。     MSDN:只要不修改Dictionary,Dictionary就可以同时支持多个阅读器。即便如此,从头到尾对一个集合进行枚举本质上并不是一个线程安全的过程。当出现枚举与写访问互相争用这种极少发生的情况时,必须在整个枚举过程中锁定集合。若允许多个线程对集合执行读写操作,您必须实现自己的同步。     所以在更新Dictionary中,都锁定了字典,防止多线程冲突。看看这个方案对你有所帮肋.如跟踪用户的话,就是把当前点的页面与在线用户实体关联上!~
      

  6.   

    我记得Session是一张表,你可以在表里查询出所有用户的信息的.当然,前提是你要在Session里放值..
      

  7.   

    这里都是讲的是实体,主要的是要知道怎么把信息存到实体里面。那个页面里面保存的内容详细到目前用户的操作(如在回贴,并且是哪个贴子,或者看哪个贴),保存这些数据是在用户操作什么的时候进行保存。是不是意味着在站点里每一个Link都绑定一个事件?
      

  8.   

    我理解的意思是 LZ要做一个在线人员管理  那么
    1.客户端需要技术AJAX长轮询(一种AJAX定时异步请求的方式)或HTTP长连接(一种借用于IFRAME保持浏览器与WEB服务器连接的技术)  
    2.在服务器端需要一个内存结构来存储在线人员(包括他的状态信息),并定时扫面用户是否在线。
      

  9.   


                lock (_UserList)
                {
                    foreach (long userId in expiredUserIdentities)
                        _UserList.Remove(userId);
                }
    这么写可以么?除非其他地方不遍历_UserList,否则一样会异常,lock不能达到预期效果
      

  10.   

    1:在每个页面的初始化的时候做判断,根据所在页面、用户信息存储到在线状态
    2:如果session过期,重新刷新用户状态(不在线)
    3:还有一种情况是ie浏览器被关闭。(这个不用考虑,为什么呢,其实只要session未过期的话,用户还是在线的。如用户在.net板块的时候直接关闭浏览器了,这个时候可当做用户还是在.net板块,只有当session过期或从浏览器进入其他页面时候才更新状态和所在模块)