第一步,构造一个简单的在线会员对象。
[Serializable]
public class OnlineMember
{
/// <summary>
/// MemberID
/// </summary>
public int MemberID { get; set; }
/// <summary>
/// SessionID
/// </summary>
public string SessionID { get; set; }
/// <summary>
/// 最后通知时间
/// </summary>
public DateTime LastNotifyTime { get; set; }
/// <summary>
/// 登录IP
/// </summary>
public string LoginIP { get; set; }
}
第二步,实现在线会员处理功能。
/// <summary>
/// 简易在线会员功能
/// 遵循类似QQ登录的原则:同一帐号登录,总是后登录的挤掉前登录的
/// </summary>
public class OnlineBiz
{
private static Dictionary<int, OnlineMember> _onlineMember = new Dictionary<int, OnlineMember>();
private static object _syncObj = new object();
private static DateTime _lastClearTime = DateTime.Now;
/// <summary>
/// 添加
/// </summary>
/// <param name="MemberID"></param>
/// <param name="SessionID"></param>
/// <param name="LoginIP"></param>
public static void Add(int MemberID, string SessionID, string LoginIP)
{
lock (_syncObj)
{
if (_onlineMember.ContainsKey(MemberID))
{
_onlineMember.Remove(MemberID);
}
OnlineMember member = new OnlineMember();
member.MemberID = MemberID;
member.SessionID = SessionID;
member.LoginIP = LoginIP;
member.LastNotifyTime = DateTime.Now;
_onlineMember.Add(MemberID, member);
}
}
/// <summary>
/// 当前会员是否有效
/// </summary>
/// <param name="MemberID"></param>
/// <param name="SessionID"></param>
/// <returns></returns>
public static bool IsValid(int MemberID, string SessionID)
{
if (!_onlineMember.ContainsKey(MemberID))
return false;
if (!_onlineMember[MemberID].SessionID.Equals(SessionID))
return false;
_onlineMember[MemberID].LastNotifyTime = DateTime.Now;
ClearTimeoutMember();
return true;
}
/// <summary>
/// 移除
/// </summary>
/// <param name="MemberID"></param>
public static void Remove(int MemberID)
{
if (_onlineMember.ContainsKey(MemberID))
_onlineMember.Remove(MemberID);
}
/// <summary>
/// 清除超时会员
/// </summary>
private static void ClearTimeoutMember()
{
int MemberLoginTimeout = int.Parse(ConfigHelper.GetParameterValue("MemberLoginTimeout"));
TimeSpan time1 = DateTime.Now - _lastClearTime;
if (time1.Minutes > MemberLoginTimeout * 5)
{
lock (_syncObj)
{
_lastClearTime = DateTime.Now;
foreach (KeyValuePair<int, OnlineMember> kvp in _onlineMember)
{
TimeSpan time2 = DateTime.Now - kvp.Value.LastNotifyTime;
if (time2.Minutes > MemberLoginTimeout)
{
_onlineMember.Remove(kvp.Key);
}
}
}
}
}
}
第三步,在会员登录成功时将会员放入队列。
//将当前会员写入在线列表
OnlineBiz.Add(member.MemberID, Session.SessionID, log.LoginIP);
第四步,实现一个在线状态维护的轮询功能,比如用AJAX定时读取某个页面,该页面中进行会员有效性检查。
//当前会员是否有效,重复登录的会员遵循后登录的挤掉前登录的原则
if (!OnlineBiz.IsValid(member.MemberID, context.Session.SessionID))
{
context.Session.Clear();
context.Response.Write(context.Request.QueryString["jsoncallback"] + "({result: 0})");
return;
}
同时,为了保证严谨性,使已踢掉的登录不能继续操作,还可在页面基类中进行同样的检查。
第五步,在客户端进行提示。
if (json.result == 0) {
alert("本帐号已在别处登录,你已被迫下线!");
self.location = "<%=Request.ApplicationPath%>/";
return;
}
需要说明的是,“超时会员清理”采用了一个偷懒且不严谨的处理方式:
- 清理动作由轮询页面触发,当后续没有会员在线的情况下,不会执行该操作。
- 假设会员超时时间为20分钟,为了稍许提高性能,我的代码每100分钟以上才会做次扫描,剔除已超时的会员。
- 假设会员超时时间为20分钟,轮询间隔时间应当小于它,比如设为2分钟、5分钟之类的比较合适。
本文作者:网友 来源: http://www.cnblogs.com/wenjian/archive/2010/04/27/1721902.html
CIO之家 www.ciozj.com 微信公众号:imciow