本文共 5280 字,大约阅读时间需要 17 分钟。
在做网络应用的时候经常要处理不处于活动的连接,对于不活动的TCP连接可以通过设置KeepAlive来触发SocketError来处理掉.但有更多的时候是使用ping和pong来处理.对于ping,pong这种做法的发起者有两种情况,分别是由server或client发起.对于由服务器发起比较损耗资源毕竟每隔一段时间都要向整个连接列发送ping,当累计到定数量没得到pong回应用的时候杀死;而对于Client发起的话server只需要记录ping时间即可,隔一段时间没有得到ping的client杀死.但两种做法似乎都要对连接列表进行一次扫描,存在大量活动连接的时候这种做法似乎并不理想.
其实可以通过一个LRU算法简单地把活动连接前置,那在处理的时候只需要关心不活动的连接即可以,LRU算法大概如下:
////// 连接描述接口 /// public interface IConnecton { ////// 获取对应在LRU算法中的节点 /// LinkedListNodeNode { get; set; } /// /// 超时操作,当LRU算法检测到应该连接超时的时候会调用该方法 /// void TimeOut(); } ////// 节点信息 /// public class Node { ////// 最后活动时间 /// public int LastActiveTime; ////// 相关连接信息 /// public IConnecton Connection; ////// 检测是否过期 /// /// /// ///public bool Detect(int cutime, int timeout) { return Math.Abs(cutime - LastActiveTime) > timeout; } }
制定一个应用接口和相应的节点类型.通过这个接口规范就可以方便定位到链表的节点上.
public void Update(IConnecton connection) { lock (this) { LinkedListNodenode = connection.Node; if (node != null) { node.Value.LastActiveTime = Environment.TickCount; mLinkedList.Remove(node); mLinkedList.AddFirst(node); } else { node = mLinkedList.AddFirst(new Node()); node.Value.LastActiveTime = Environment.TickCount; node.Value.Connection = connection; connection.Node = node; } } }
当一个项更新的时候就不再需要遍历链表查询,这样就能节省大量查询上的损耗.当然一个完整的LRU检测机制不是要一个timer来驱动,完全代码如下:
////// 基于LRU算法的连接检测 /// public class LRUDetect : IDisposable { ////// 构建检测器 /// /// 超时时间以毫秒为单位 public LRUDetect(int timeout) { mTimeout = timeout; mTimer = new System.Threading.Timer(OnDetect, null, mTimeout, mTimeout); } private int mTimeout; private System.Threading.Timer mTimer; private LinkedListmLinkedList = new LinkedList (); /// /// 更新连接 /// /// 连接信息 public void Update(IConnecton connection) { lock (this) { LinkedListNodenode = connection.Node; if (node != null) { node.Value.LastActiveTime = Environment.TickCount; mLinkedList.Remove(node); mLinkedList.AddFirst(node); } else { node = mLinkedList.AddFirst(new Node()); node.Value.LastActiveTime = Environment.TickCount; node.Value.Connection = connection; connection.Node = node; } } } /// /// 删除连接 /// /// 连接信息 public void Delete(IConnecton connection) { lock (this) { LinkedListNodenode = connection.Node; if (node != null) { node.Value.Connection = null; mLinkedList.Remove(node); } } } private void OnDetect(object state) { lock (this) { int cutime = Environment.TickCount; LinkedListNode last = mLinkedList.Last; while (last != null && last.Value.Detect(cutime, mTimeout)) { last.Value.Connection.TimeOut(); last.Value.Connection = null; mLinkedList.RemoveLast(); last = mLinkedList.Last; } } } /// /// 连接描述接口 /// public interface IConnecton { ////// 获取对应在LRU算法中的节点 /// LinkedListNodeNode { get; set; } /// /// 超时操作,当LRU算法检测到应该连接超时的时候会调用该方法 /// void TimeOut(); } ////// 节点信息 /// public class Node { ////// 最后活动时间 /// public int LastActiveTime; ////// 相关连接信息 /// public IConnecton Connection; ////// 检测是否过期 /// /// /// ///public bool Detect(int cutime, int timeout) { return Math.Abs(cutime - LastActiveTime) > timeout; } } /// /// 释放对象 /// public void Dispose() { if (mTimer != null) { mTimer.Dispose(); mLinkedList.Clear(); } } }
转载地址:http://setfz.baihongyu.com/