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

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

主动

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

被动

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

模式选择

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

检测算法

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

以下给出相关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();
}
}

TCP连接有效性检测方法的更多相关文章

  1. TCP连接的关闭

    原文地址:http://lib.csdn.net/article/computernetworks/17264   TCP连接的关闭有两个方法close和shutdown,这篇文章将尽量精简的说明它们 ...

  2. TCP连接异常断开检测(转)

    TCP是一种面向连接的协议,连接的建立和断开需要通过收发相应的分节来实现.某些时候,由于网络的故障或是一方主机的突然崩溃而另一方无法检测到,以致始终保持着不存在的连接.下面介绍一种方法来检测这种异常断 ...

  3. (转)TCP连接异常断开检测

    TCP是一种面向连接的协议,连接的建立和断开需要通过收发相应的分节来实现.某些时候,由于网络的故障或是一方主机的突然崩溃而另一方无法检测到,以致始终保持着不存在的连接.下面介绍一种方法来检测这种异常断 ...

  4. 链路的有效性检测 及 基于TCP的通信为什么需要RETRY

    一.链路的有效性检测 当网络发生单通.连接被防火墙Hang住.长时间GC或者通信线程发生非预期异常时,会导致链路不可用且不易被及时发现. 特别是异常发生在凌晨业务低谷期间,当早晨业务高峰期到来时,由于 ...

  5. 怎样及时检测出非正常断开的TCP连接(zz)

    此处的”非正常断开”指TCP连接不是以优雅的方式断开,如网线故障等物理链路的原因,还有突然主机断电等原因有两种方法可以检测:1.TCP连接双方定时发握手消息 2.利用TCP协议栈中的KeepAlive ...

  6. TCP短连接TIME_WAIT问题解决方法大全

    tcp连接是网络编程中最基础的概念,基于不同的使用场景,我们一般区分为“长连接”和“短连接”,长短连接的优点和缺点这里就不详细展开了,有心的同学直接去google查询,本文主要关注如何解决tcp短连接 ...

  7. 【转】TCP连接突然断开的处理方法

    TCP是因特网中的传输层协议,使用三次握手协议建立连接,下面是TCP建立连接的全过程. TCP断开连接的过程:TCP四次挥手. TCP/IP 协议簇分层结构 数据链路层主要负责处理传输媒介等众多的物理 ...

  8. TCP连接状态详解及TIME_WAIT过多的解决方法

    上图对排除和定位网络或系统故障时大有帮助,但是怎样牢牢地将这张图刻在脑中呢?那么你就一定要对这张图的每一个状态,及转换的过程有深刻地认识,不能只停留在一知半解之中.下面对这张图的11种状态详细解释一下 ...

  9. 在实战中使用nginx-rtmp遇到的TCP连接问题分析

    在实战中使用nginx-rtmp遇到的TCP连接问题分析 背景 前段时间公司做了一次体育赛事的现场直播,网络由某通信公司负责搭建,主要测试5G CPE上行网络的带宽和稳定性,为了做到万无一失,他们同时 ...

随机推荐

  1. git 修改用户名和密码

    初次运行 Git 前的配置 一般在新的系统上,我们都需要先配置下自己的 Git 工作环境.配置工作只需一次,以后升级时还会沿用现在的配置.当然,如果需要,你随时可以用相同的命令修改已有的配置. Git ...

  2. 关机,重启BAT命令

    关机命令shutdown -s -t 重启命令 shutdown -r -t

  3. 读《31天学会CRM项目开发》记录4 - WEB服务配置

    好几天没有更新记录了,因为最近都在看本书的基础内容,然后跟着练习.等看到数据库部分,就晕菜了,只能草草浏览一遍,想在后面的实战中再加强. 下面是对IIS 和ASP.NET的配置! 一.什么是IIS? ...

  4. 创建多线程的方式:继承Thread类和实现Runnable接口

    1.通过继承Thread类的方式创建多线程(这里只是简单的代码演示创建多线程的方法) package com.baozi.exer; public class ThreadDemo { public ...

  5. C# 异步编程之 Task 的使用

    (说明:随笔内容为学习task的笔记,资料来源:https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task?redi ...

  6. 纯css修改单选、复选按钮样式

    只支持IE9及以上 html <label><input class="radio" type="radio" name="radi ...

  7. Java课程之团队开发(NABCD需求分析)

    N.需求 1.学生基本的录入课程功能 2.学生对于空教室使用的需求(自习或者是活动占用) 3.学生对于具体课程的查询需求 A.做法 1.制作出基于安卓的课程查询,录入以及教室查询应用软件 B.好处 1 ...

  8. composer 实现自动加载原理

    简介 一般在框架中都会用到composer工具,用它来管理依赖.其中composer有类的自动加载机制,可以加载composer下载的库中的所有的类文件.那么composer的自动加载机制是怎么实现的 ...

  9. AWS MVC 详解

    由于新工作是在AWS PaaS平台上进行开发,为不耽误工作,先整理一下AWS MVS的使用规范,快速上手.对AWS PaaS平台的相关介绍留到以后再来补充.本文几乎是对官方学习文档的整理,有遗漏的后补 ...

  10. mvc根据绝对路径下载文件

    首先页面需要一个a标签直接指向下载文件的Action并传值:图片地址,以及图片名称(记住要带后缀名的). 然后是Action里面的代码. SiteHelper.DownloadFile(fileUrl ...