在写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. 手写数字识别 ----卷积神经网络模型官方案例注释(基于Tensorflow,Python)

    # 手写数字识别 ----卷积神经网络模型 import os import tensorflow as tf #部分注释来源于 # http://www.cnblogs.com/rgvb178/p/ ...

  2. sublime text 3启动报错"swallow_startup_errors"解决方法

    启动sublime text 3报错: anaconda插件连接jsonserver服务出现错误 解决方法: 首选项 -- package settings -- Anaconda -- settin ...

  3. 一年前的很水的渣网页(第一次html试水)

    <!doctype html> <html lang="zh-cn"> <base target="_blank" /> & ...

  4. Android的自定义View及View的绘制流程

    目标:实现Android中的自定义View,为理清楚Android中的View绘制流程“铺路”. 想法很简单:从一个简单例子着手开始编写自定义View,对ViewGroup.View类中与绘制View ...

  5. USACO 邮票 Stamps

    f[x]表示组成 x 最少需要的邮票数量 一一举例 最多贴5张邮票,有三种邮票可用,分别是1分,3分,8分 组成0分需要0张邮票 ——f[0]=0 组成1分需要在0分的基础上加上一张1分邮票 ——f[ ...

  6. 神奇高效的Linux命令行

    一.为什么要学linux命令 Linux是由命令行组成的操作系统,精髓在命令行,无论图形界面发展到什么水平,命令行方式的操作永远是不会变的.Linux命令有许多强大的功能:从简单的磁盘操作.文件存取, ...

  7. 封装redis

    封装redis import redis # r = redis.Redis() class MyRedis(): def __init__(self,ip,password,port=6379,db ...

  8. ko数组

    数组属性监控 如果你想发现并响应一个对象的改变,就应该用监控属性(observables).如果你想发现并响应一个集合的变化,就该用监控属性数组 (observableArray).监控属性数组在显示 ...

  9. DAO模式

    什么是DAO模式: DAO(Data Access Object Pattern)用于将低层的数据操作API与上层的业务逻辑层分离,其主要涉及以下几个部分: 1.Data Access Object ...

  10. 为什么导入本地jquery.js老是无效?(已解决)

    我从jquery官网里复制过来jquery.js内容,然后粘贴到本地,但是引用的时候总是无效. 在翻看脚本所在目录,无意间发现脚本文件是个jquery.js.js,    原来是我的文件的扩展名的问题 ...