一个简单基于LRU连接检测实现
在做网络应用的时候经常要处理不处于活动的连接,对于不活动的TCP连接可以通过设置KeepAlive来触发SocketError来处理掉.但有更多的时候是使用ping和pong来处理.对于ping,pong这种做法的发起者有两种情况,分别是由server或client发起.对于由服务器发起比较损耗资源毕竟每隔一段时间都要向整个连接列发送ping,当累计到定数量没得到pong回应用的时候杀死;而对于Client发起的话server只需要记录ping时间即可,隔一段时间没有得到ping的client杀死.但两种做法似乎都要对连接列表进行一次扫描,存在大量活动连接的时候这种做法似乎并不理想.
其实可以通过一个LRU算法简单地把活动连接前置,那在处理的时候只需要关心不活动的连接即可以,LRU算法大概如下:

/// <summary> /// 连接描述接口 /// </summary> public interface IConnecton { /// <summary> /// 获取对应在LRU算法中的节点 /// </summary> LinkedListNode<LRUDetect.Node> Node { get; set; } /// <summary> /// 超时操作,当LRU算法检测到应该连接超时的时候会调用该方法 /// </summary> void TimeOut(); } /// <summary> /// 节点信息 /// </summary> public class Node { /// <summary> /// 最后活动时间 /// </summary> public int LastActiveTime; /// <summary> /// 相关连接信息 /// </summary> public IConnecton Connection; /// <summary> /// 检测是否过期 /// </summary> /// <param name="cutime"></param> /// <param name="timeout"></param> /// <returns></returns> public bool Detect(int cutime, int timeout) { return Math.Abs(cutime - LastActiveTime) > timeout; } }
制定一个应用接口和相应的节点类型.通过这个接口规范就可以方便定位到链表的节点上.
public void Update(IConnecton connection) { lock (this) { LinkedListNode<LRUDetect.Node> node = 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来驱动,完全代码如下:
/// <summary> /// 基于LRU算法的连接检测 /// </summary> public class LRUDetect : IDisposable { /// <summary> /// 构建检测器 /// </summary> /// <param name="timeout">超时时间以毫秒为单位</param> public LRUDetect(int timeout) { mTimeout = timeout; mTimer = new System.Threading.Timer(OnDetect, null, mTimeout, mTimeout); } private int mTimeout; private System.Threading.Timer mTimer; private LinkedList<Node> mLinkedList = new LinkedList<Node>(); /// <summary> /// 更新连接 /// </summary> /// <param name="connection">连接信息</param> public void Update(IConnecton connection) { lock (this) { LinkedListNode<LRUDetect.Node> node = 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; } } } /// <summary> /// 删除连接 /// </summary> /// <param name="connection">连接信息</param> public void Delete(IConnecton connection) { lock (this) { LinkedListNode<LRUDetect.Node> node = connection.Node; if (node != null) { node.Value.Connection = null; mLinkedList.Remove(node); } } } private void OnDetect(object state) { lock (this) { int cutime = Environment.TickCount; LinkedListNode<Node> last = mLinkedList.Last; while (last != null && last.Value.Detect(cutime, mTimeout)) { last.Value.Connection.TimeOut(); last.Value.Connection = null; mLinkedList.RemoveLast(); last = mLinkedList.Last; } } } /// <summary> /// 连接描述接口 /// </summary> public interface IConnecton { /// <summary> /// 获取对应在LRU算法中的节点 /// </summary> LinkedListNode<LRUDetect.Node> Node { get; set; } /// <summary> /// 超时操作,当LRU算法检测到应该连接超时的时候会调用该方法 /// </summary> void TimeOut(); } /// <summary> /// 节点信息 /// </summary> public class Node { /// <summary> /// 最后活动时间 /// </summary> public int LastActiveTime; /// <summary> /// 相关连接信息 /// </summary> public IConnecton Connection; /// <summary> /// 检测是否过期 /// </summary> /// <param name="cutime"></param> /// <param name="timeout"></param> /// <returns></returns> public bool Detect(int cutime, int timeout) { return Math.Abs(cutime - LastActiveTime) > timeout; } } /// <summary> /// 释放对象 /// </summary> public void Dispose() { if (mTimer != null) { mTimer.Dispose(); mLinkedList.Clear(); } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2012-04-08 使用Silverlight实现网盘功能