通过LRU实现通用高效的超时连接探测
编写网络通讯都要面对一个问题,就是要把很久不存活的死连接清除,如果不这样做那死连接最终会占用大量内存影响服务运作!在实现过程中一般都会使用ping,pong原理,通过ping,pong来更新连接的时效性,最后通过扫描连接列表来清除掉。虽然这种做法比较简单,但很难抽取出通用性的封装,扫描整个列表复杂度也比较高。以下讲解如何通过LRU算法实现一个通用高效的探测超时连接功能类。
什么是LRU
在这里还是要大概介绍一下LRU,LRU算法的设计原则是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小.也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰.当然在这里并不需要使用到自动淘汰机制,只需要把未位到达超时的连接清除即可。
在C#中如何实现LRU
C#并不存在这样的数据结构,不过有一个结构很适合实现LRU,这个结构就是LinkedList双向链表,通过以下结构图就容易理解通过LinkedList实现LRU

通过LinkedList的功能我们可以把活越项先移出来,然后再把项移到头部。在这里需要注意LinkedList的Remove方法,它有两个重载版本,两个版本的复杂度不一样。一个是O(n)一个是O(1)所以使用上一定要注意,否则在数据多的情况下效率差别巨大(这些细节都可以通过源代码来查看)!
代码实现
前面已经大概讲述的原理,接下来要做的就是代码实现了。第一步需要制订一个基础可控测对象规则接口,这样就可以让现有的已经实现的功能实现它并可得到相关功能的支持。
public interface IDetector
{
double ActiveTime
{ get; set; }
LinkedListNode<IDetector> DetectorNode
{
get;
set;
}
}
接口定义了两个属性,一个是最近活越时间,另一个就是LinkedListNode<IDetector>这个属性比交关键,通过LinkedListNode<IDetector>可以让LinkedList在Remove时复杂度为O(1).接下来就要针对基于LRU算法处理超时制定一个应用规则
public interface ILRUDetector
{
void Update(IDetector item); void Detection(int timeout); double GetTime(); Action<IList<IDetector>> Timeout { get; set; }
}
规则也是比较简单,Update用于更新跟踪对象,一般在处理接受ping或pong包后进行调用;Detection方法是探测超出指定时间的对象,时间当位是毫秒,如果存在有超时的对象则触发Timeout事件;GetTime是获取探测器已经运行的时间单位毫秒!规则定好了那接着要做的事实就是要实现它:
class LRUDetector : ILRUDetector, IDisposable
{
public LRUDetector()
{
mTimeWatch = new System.Diagnostics.Stopwatch();
mTimeWatch.Restart();
}
private Buffers.XSpinLock xSpinLock = new Buffers.XSpinLock();
private System.Diagnostics.Stopwatch mTimeWatch;
private LinkedList<IDetector> mItems = new LinkedList<IDetector>();
public Action<IList<IDetector>> Timeout
{
get; set;
}
public void Detection(int timeout)
{
double time = GetTime();
List<IDetector> result = new List<IDetector>();
using (xSpinLock.Enter())
{
LinkedListNode<IDetector> last = mItems.Last;
while (last != null && (time - last.Value.ActiveTime) > timeout)
{
mItems.Remove(last);
result.Add(last.Value);
last.Value.DetectorNode = null;
last = mItems.Last;
}
}
if (Timeout != null && result.Count > )
Timeout(result);
}
public void Update(IDetector item)
{
using (xSpinLock.Enter())
{
if (item.DetectorNode == null)
item.DetectorNode = new LinkedListNode<IDetector>(item);
item.ActiveTime = GetTime();
if (item.DetectorNode.List == mItems)
mItems.Remove(item.DetectorNode);
mItems.AddFirst(item);
}
}
public void Dispose()
{
mItems.Clear();
}
public double GetTime()
{
return mTimeWatch.Elapsed.TotalMilliseconds;
}
}
代码并不复杂,相信不用过多解释也能看懂相关操作原理。
测试
既然功能已经实现,接下来就要对代码进行测试看运行效果。测试代码比较简单首先开启一个Timer定时执行Detection,另外开一个线程去调用Update方法
class Program
{
public class TestDetector : IDetector
{
public double ActiveTime { get; set; }
public string Name { get; set; }
public LinkedListNode<IDetector> DetectorNode { get; set; }
}
static void Main(string[] args)
{
LRUDetector lRUDetector = new LRUDetector();
lRUDetector.Timeout = (items) =>
{
foreach (TestDetector item in items)
Console.WriteLine($"{(item.Name)} timeout {lRUDetector.GetTime() - item.ActiveTime}ms");
};
System.Threading.Timer timer = null;
timer = new System.Threading.Timer(o =>
{
timer.Change(-, -);
lRUDetector.Detection();
timer.Change(, );
}, null, , );
System.Threading.ThreadPool.QueueUserWorkItem(o =>
{
int i = ;
while (true)
{
System.Threading.Thread.Sleep();
i++;
TestDetector testDetector = new TestDetector();
testDetector.Name = "my name is " + i;
lRUDetector.Update(testDetector);
}
});
Console.Read();
}
}
运行效果:

通过LRU实现通用高效的超时连接探测的更多相关文章
- linux上搭建ftp、vsftp, 解决访问ftp超时连接, 解决用户指定访问其根目录,解决ftp主动连接、被动连接的问题
linux上搭建ftp 重要 解决如何搭建ftp 解决用户指定访问其根目录 解决访问ftp超时连接 解决ftp主动连接.被动连接的问题 1.安装ftp ...
- TCP连接探测中的Keepalive和心跳包
TCP连接探测中的Keepalive和心跳包 tcp keepalive 心跳 保活 Linuxtcp心跳keepalive保活1. TCP保活的必要性 1) 很多防火墙等对于空闲socket自动关闭 ...
- 10w定时任务,如何高效触发超时
一.缘起 很多时候,业务有定时任务或者定时超时的需求,当任务量很大时,可能需要维护大量的timer,或者进行低效的扫描. 例如:58到家APP实时消息通道系统,对每个用户会维护一个APP到服务器的TC ...
- MYSQL超时连接问题(com.mysql.jdbc.MysqlIO.readFully)
应用服务器连接mysql,有时候会出现以下异常: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.jav ...
- 高效管理http连接
1.Http连接基础 Http协议承载了互联网上的主要流量,然而说到传输,还要回归到最基本的网络分层模型TCP/IP.TCP/IP是全球计算机及网络设备都在使用的一种常用的分组交互网络分层协议集.客户 ...
- linux下的epoll怎样高效处理百万连接
开发高性能网络程序时.windows开发人员们言必称iocp,linux开发人员们则言必称epoll.大家都明确epoll是一种IO多路复用技术,能够很高效的处理数以百万计的socket句柄,比起曾经 ...
- 通用高效的数据修复方法:Row level repair
导读:随着大数据的进一步发展,NoSQL 数据库系统迅速发展并得到了广泛的应用.其中,Apache Cassandra 是最广泛使用的数据库之一.对于 Cassandra 的优化是大家研究的热点,而 ...
- 抓到 Netty 一个 Bug,顺带来透彻地聊一下 Netty 是如何高效接收网络连接的
本系列Netty源码解析文章基于 4.1.56.Final版本 对于一个高性能网络通讯框架来说,最最重要也是最核心的工作就是如何高效的接收客户端连接,这就好比我们开了一个饭店,那么迎接客人就是饭店最重 ...
- svn 连接超时,连接失败解决办法
1.确认服务是否开启 2.Windows防火墙是否开启,如开启则关闭防火墙 3.安全软件是否将3306与443端口关闭. 关闭后无法连接
随机推荐
- ios12版本以上键盘唤起后,收回页面不回滚问题
最近提测后,发现ios升级到12版本之后,引发了调用确认框的组件之后按钮失效问题. 然后开始了升级复现bug的各种操作,最后发现是完成后键盘收起后,页面没有回滚,因为页面整体被推上了一定高度,导致错位 ...
- 让java代码在Idea外面运行起来
今天在写聊天程序,终于写到双方通信的时候,发现idea只能开一个客户端.虽说可以开多线程来实现多开,但是懒得改动代码,所以我就试试能不能把jar包导出来运行.首先我用maven自带的工具打了jar包, ...
- easyUI 创建有复选框的table.datagrid
table : function(data){ pt.v.table.datagrid({ // singleSelect:true, height:295, columns:[[ {field:'x ...
- Android中ListView的简单使用
动态添加单行列表: 首先前提是你的布局文件里有一个ListView 单行列表的添加只需要一个list集合即可,使用ArrayAdapter数组适配器绑定更新就行了 首先声明一个ArrayAdapter ...
- mac上安装iterm2的一些步骤记录
1.首先到item官网上下载item 下载地址 http://iterm2.com/ 2.把iitem2设置为默认终端: 3.设置快速打开关闭的hotkey 我们这里设置为command + T键 ...
- Windows下搭建Redis集群
Redis集群: 如果部署到多台电脑,就跟普通的集群一样:因为Redis是单线程处理的,多核CPU也只能使用一个核, 所以部署在同一台电脑上,通过运行多个Redis实例组成集群,然后能提高CPU的利用 ...
- Three.js学习笔记03--光
1. 光源基类 在Threejs中,光源用Light表示,它是所有光源的基类.它的构造函数是: THREE.Light ( hex ) 它有一个参数hex,接受一个16进制的颜色值.例如要定义一种红色 ...
- Batch入门教程丨第一章:部署与Hello World!(上)
Batch入门教程 在本教程中,您将了解并学习与Windows Batch有关的知识和编程方法,用以解决在日常生活中所遇到的简单问题,或者利用Windows Batch建立一个最初级的编程思维方式. ...
- [Swift]LeetCode850. 矩形面积 II | Rectangle Area II
We are given a list of (axis-aligned) rectangles. Each rectangle[i] = [x1, y1, x2, y2] , where (x1, ...
- MiniProfiler监控Asp.Net MVC5和EF性能
1. 安装依赖包 在web项目打开nuget包管理器搜索 MiniProfiler.Mvc5和MiniProfiler.EF6安装. 2. 在Global.asax中添加配置代码 protected ...