编写网络通讯都要面对一个问题,就是要把很久不存活的死连接清除,如果不这样做那死连接最终会占用大量内存影响服务运作!在实现过程中一般都会使用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 的优化是大家研究的热点,而 ...
-
svn 连接超时,连接失败解决办法
1.确认服务是否开启 2.Windows防火墙是否开启,如开启则关闭防火墙 3.安全软件是否将3306与443端口关闭. 关闭后无法连接
-
通用高效字符串匹配--Sunday算法
字符串匹配(查找)算法是一类重要的字符串算法(String Algorithm).有两个字符串, 长度为m的haystack(查找串)和长度为n的needle(模式串), 它们构造自同一个有限的字母表 ...
随机推荐
-
iOS 组件化方案探索
来自bang's blog http://blog.cnbang.net/tech/3080/
-
MVC4中基于bootstrap和HTML5的图片上传Jquery自定义控件
场景:mvc4中上传图片,批量上传,上传前浏览,操作.图片进度条. 解决:自定义jquery控件 没有解决:非图片上传时,会有浏览样式的问题; 解决方案; 1.样式 – bootstrap 的css和 ...
-
通过单元测试理解spring容器以及dubbo+zookeeper单元测试异常处理
一.先说一个结论:单元测试与主项目的spring容器是隔离的,也就是说,单元测试无法访问主项目spring容器,需要自己加载spring容器. 接下来是代码实例,WEB主项目出于运行状态,单元测试中可 ...
-
7 Serial Configuration 理解(二)
*Serial Configuration Mode 串行配置模式分为:Master Serial 和 Slave Serial (如下图)两类: 两者的区别在与CCLK的输入输出方向:主动模式下为输 ...
-
Ant里面神奇的fork
最近两天一直在处理ant运行java程序的一个问题,用IDE直接运行类里面的main函数一切正常,但用ant跑该函数就报错误,错误的原因是运行ant任务时调用的是AntClasloader,而IDE里 ...
-
linux下pcf8563驱动时钟使用
环境: HelperA64开发板 Linux3.10内核 时间:2019.01.17 目标:PCF8563实时时钟驱动的使用 问题:因为pcf8563的驱动是linux内核自带的,网上也有很多分析的方 ...
-
Oracle dba权限下修改用户密码 授予用户权限 解锁用户
1.修改用户密码 alter user scott identified by 123 2.授予用户权限 grant connect,resource to scott 3.解锁用户 alter us ...
-
POJ 3233 Matrix Power Series 【经典矩阵快速幂+二分】
任意门:http://poj.org/problem?id=3233 Matrix Power Series Time Limit: 3000MS Memory Limit: 131072K To ...
-
安装pyautogui时报错备注
python3.6用pip安装pyautogui时报错,找了蛮多方法都不行,最后通过安装低版本的pyautogui解决,这里备注下 报错图 解决方法: pip install pyautogui==0 ...
-
如何使用JMETER从JSON响应中提取数据
如果你在这里,可能是因为你需要使用JMeter从Json响应中提取变量. 好消息!您正在掌握掌握JMeter Json Extractor的权威指南.作为Rest API测试指南的补充,您将学习掌握J ...