首页 技术 正文
技术 2022年11月10日
0 收藏 683 点赞 2,433 浏览 2915 个字

在写TCP服务的时候经常需要面对的问题就是如何知道一个TCP连接当前是否有效,但这个问题对很多初入门的同学来说是很困惑的,主要原因是当对方关闭连接后,另一方无法有效的知道;对于同步操作来说可以通过设置操作超时来解决,但异步操作则没有这样方便的了,那只能等keepalive的检测完成引发异步回调了。

那在编写应用的时候一般通讯什么方式来检测连接的有效性呢?解决方法一般有两种一种是设置TCP的keepalive时间,另一种则是通过Ping,Pong的方式来实现。前者相对比较简单通过socket.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null)方法设置即可,以下主要但要通过Ping,Pong的方式来实现应用层面的TCP连接有效性检测。通过Ping,Pong来处理有两种方式:服务器主动和被动。

主动

这种方式主要是由服务器发起,然后由客户端响应;服务检测每个连接Pong响应情况,如果连接在一段时间内没有Pong回应则把相应连接关闭并处理相关会话资源。

TCP连接有效性检测方法

被动

这种方式由Client发起Ping然后由服务端回应Pong,如果Client是同步操作的话其实服务端是不需要应答Pong包。服务端检测每个连接最近的Ping时间,如果超过一段时间没有Ping的情况把相应连接关闭并处理相关会话资源。

TCP连接有效性检测方法

模式选择

从上面的两种方式来看显然是被动模式更节省服务器资源,如果采用主动的话服务器还必须启用一个定时器对现有在线接进行发送Ping操作;被动模式就完全不需要了,只有接收到客户端Ping回应一个Pong操作。

检测算法

一般情况会用一个定时器隔一段时间对所有Client检测一次,看对应的Ping时间是否超时,如果是则直接关闭和释放资源。但这样是要对所有连接进行扫描,其实在应用中只有很小部分连接是无效的,如果针对所有在线连接进行一个扫描那的确一个比较花成本的工作。为了解决全扫描的情况,可以采用一种简单的算法LRU,通过LRU算法在检测的时候只要扫冷区数据即可,这样就可以达到只扫描Ping超时的连接。LRU具体处理结构如下:

TCP连接有效性检测方法

以下给出相关LRU实现的c#版本代码:

/// <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();
}
}
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,488
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,903
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,737
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,489
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,128
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,290