版权声明:本文为CSDN博主「b哈利路亚d」的原创文章,重新编辑发布,请尊重原作者的劳动成果,转载的时候附上原文链接:https://blog.csdn.net/lanwilliam/article/details/51698807

Socket本身无法很好的捕获连接断开事件,或者说根本没这功能。总不能每次发生数据通讯时,通过异常来判断吧。

所以经过了各种测试及查询(这里还是要感谢国外的友人们,鄙视一下国人),总算找到一种相对稳定的方法。

该方法利用了tcp/ip协议本省的keep-alive规则。

keep-alive简单来说,就是tcp协议中制定的心跳检测,用来判断连接是否存活。默认是不启动的,需要进行设置。

serverFullAddr = new IPEndPoint(IPAddress.Any, portNo);//设置IP,端口
server = new TcpListener(serverFullAddr);
server.Start();
// 启用keep-alive
server.Server.IOControl(IOControlCode.KeepAliveValues, GetKeepAliveData(), null);
server.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);

上面是server端演示代码,用的是tcplistener,毕竟比较方便。而且用来和DTU通讯的时候,使用的NetworkStream,这个相对好用

client = server.AcceptTcpClient();
// 启用keep-alive
client.Client.IOControl(IOControlCode.KeepAliveValues, GetKeepAliveData(), null);
client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);

上面是客户端启用的设置。

按照查询到的理论,应该任意一方面设置了就可以,不过我这里都启用了,姑且算保险吧。

然后就是IOControl设置的数据了。

private byte[] GetKeepAliveData()
{
uint dummy = 0;
byte[] inOptionValues = new byte[Marshal.SizeOf(dummy) * 3];
BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0);
BitConverter.GetBytes((uint)3000).CopyTo(inOptionValues, Marshal.SizeOf(dummy));//keep-alive间隔
BitConverter.GetBytes((uint)500).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2);// 尝试间隔
return inOptionValues;
}

keep-alive如果使用windows默认,可能2个小时才会发送一次心跳,我这里检测设备在线,肯定不能这么长时间,我的读数频率都是以分钟作为单位的,出于各方面考虑
我这里设置的keep-alive每3秒发送一次。如果对方没有响应,每0.5秒后发送一次确认,如果连续3次没有回应,连接会自动变成TcpState.Established。

这里说一下,查询过程中发现很多人使用socket去poll来进行判断,在测试中,发现不好用,响应不及时,后来多方查找资料并测试,发现通过系统本身的连接来进行判断比较准确,方法如下:

/// <summary>
/// THIS FUNCTION WILL CHECK IF CLIENT IS STILL CONNECTED WITH SERVER.
/// </summary>
/// <returns>FALSE IF NOT CONNECTED ELSE TRUE</returns>
public bool isClientConnected(TcpClient ClientSocket)
{
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();

TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections();

foreach (TcpConnectionInformation c in tcpConnections)
{
TcpState stateOfConnection = c.State;

if (c.LocalEndPoint.Equals(ClientSocket.Client.LocalEndPoint) && c.RemoteEndPoint.Equals(ClientSocket.Client.RemoteEndPoint))
{
if (stateOfConnection == TcpState.Established)
{
return true;
}
else
{
return false;
}

}

}

return false;
}

这样解决办法就简单了。

单独写一个CheckAlive的线程进行检测,然后抛出事件并移除连接就ok。

public void StartCheckAlive()
{
Thread th = new Thread(new ThreadStart(CheckAlive));
th.IsBackground = true;
th.Start();
TCPLogger.Log("CheckAlive线程已启动");
}

private void CheckAlive()
{
Thread.Sleep(10000);
while(isListen)
{
try
{
lock (ClientList)
{
foreach (ClientItem item in ClientList)
{
//if (item.Client.Client.Poll(500, System.Net.Sockets.SelectMode.SelectRead) && (item.Client.Client.Available == 0))

if (!isClientConnected(item.Client))
{
removeQueue.Enqueue(item);
continue;
}
}
while (removeQueue.Count > 0)
{
ClientItem item = removeQueue.Dequeue();
clientList.Remove(item);
try
{
TCPLogger.Log("关闭客户端连接");
item.Client.Close();

}
catch (Exception ex)
{
TCPLogger.Log("关闭客户端连接", ex);
}
TCPLogger.Log("CheckAlive移除链接:" + item.RegCode);
if (OnClientRemoved != null)
OnClientRemoved(item.RegCode);
}
}

}catch(Exception e)
{
TCPLogger.Log("CheckAlive异常.", e);
}

Thread.Sleep(500);
}
}

C# Socket keeplive 心跳检测实例的更多相关文章

  1. socket心跳检测

    一.什么是心跳检测 判断对方(设备,进程或其它网元)是否正常动行,一般采用定时发送简单的通讯包,如果在指定时间段内未收到对方响应,则判断对方已经当掉.用于检测TCP的异常断开. 基本原因是服务器端不能 ...

  2. Mina 系列(四)之KeepAliveFilter -- 心跳检测

    Mina 系列(四)之KeepAliveFilter -- 心跳检测 摘要: 心跳协议,对基于CS模式的系统开发来说是一种比较常见与有效的连接检测方式,最近在用MINA框架,原本自己写了一个心跳协议实 ...

  3. 记录初试Netty(2)-服务端心跳检测

    今天在在搭建的netty框架中添加心跳机制,特此记录一下:      1.什么是心跳机制? 心跳是在TCP长连接中,客户端和服务端定时向对方发送数据包通知对方自己还在线,保证连接的有效性的一种机制 在 ...

  4. websocket-heartbeat-js心跳检测库正式发布

    前言: 两年前写了一篇websocket心跳的博客——初探和实现websocket心跳重连.  阅读量一直比较大,加上最近考虑写一个自己的npm包,因此就完成了一个websocket心跳的检测库.在这 ...

  5. wifidog源码分析 - 认证服务器心跳检测线程

    引言 但wifidog启动时,会自动启动认证服务器心跳检测线程,此线程默认每隔60s与认证服务器交互一次,会将路由器的信息(系统启动时长,内存使用情况和系统平均负载)告知认证服务器,并通过一个&quo ...

  6. Netty实践二(心跳检测)

    我们使用Socket通信一般经常会处理多个服务器之间的心跳检测,一般来讲,我们去维护服务器集群,肯定要有一台或几台服务器主机(Master),然后还应该有N台(Slave),那么我们的主机肯定要时时刻 ...

  7. 基于MINA实现server端心跳检测(KeepAliveFilter)

    MINA自带了对心跳协议的支持,可以对心跳做出细致的配置,本文在次基础上实现了server端对client端的心跳检测. 在开始之前先简单介绍下keepAlive的机制: 首先,需要搞清楚TCP ke ...

  8. Netty--数据通信和心跳检测

    数据通信 概述: netty的ReadTimeOut实现方案3 服务端: public class Server { public static void main(String[] args) th ...

  9. 切实解决socket连接掉线检测

    原文:切实解决socket连接掉线检测 版权声明:欢迎转载,但是请保留出处说明 https://blog.csdn.net/lanwilliam/article/details/51698807 新公 ...

随机推荐

  1. Mongoose 内置 CURD 方 法、扩展 Mongoose Model 的静态方法和 实例方法

    Mongoose 内置 CURD 方 法 Mongoose 内置 CURD 方 法文档地址:https://mongoosejs.com/docs/queries.html 常用的方法如下: Mode ...

  2. 关于window.getSelection

    window.getSelection(),返回一个Selection对象,表示用户选择的文本范围或光标的当前位置. selection对象先来看下面两个selection结果:selection对象 ...

  3. 在 Ubuntu/Debian 下安装 PHP7.3 教程

    介绍 最近的 PHP 7.3.0 已经在 2018 年12月6日 发布 GA,大家已经可以开始第一时间体验新版本了,这里先放出 PHP7.3 安装的教程以便大家升级. 适用系统: Ubuntu 18. ...

  4. BERT模型

    BERT模型是什么 BERT的全称是Bidirectional Encoder Representation from Transformers,即双向Transformer的Encoder,因为de ...

  5. 哈希表查找(散列表查找) c++实现HashMap

    算法思想: 哈希表 什么是哈希表 在前面讨论的各种结构(线性表.树等)中,记录在结构中的相对位置是随机的,和记录的关键字之间不存在确定的关系,因此,在结构中查找记录时需进行一系列和关键字的比较.这一类 ...

  6. H3C交换机如何删除VLAN

    H3C交换机如何删除VLAN,如果直接使用“undo vlan”是删不干净的,因为配置VLAN时还配置过接口. 1.首先通过console口或telnet连接三层交换机,进入用户视图模式”<H3 ...

  7. UltraISO安装windows10时0x8007000D错误解决办法

    进入安装界面之后提示错误:windows无法打开所需的文件 F:\Sources\install.wim.请确保安装所需的所有文件可用,并重新启动安装.错误代码:0x8007000D 原因: 肯定是i ...

  8. SpringBoot项目中的全局异常处理器 Failed to invoke @ExceptionHandler method

    文件下载代码 @RequestMapping(value = { "/data/docking/picture/{id}/{empi}" }) public JsonApi pic ...

  9. java中为什么notify()可能会导致死锁,而notifyAll()则不会

    简单的说,notify()只唤醒一个正在等待的线程,当该线程执行完以后施放该对象的锁,而没有再次执行notify()方法,则其它正在等待的线程 则一直处于等待状态,不会被唤醒而进入该对象的锁的竞争池, ...

  10. PhpStorm2019 代码自动换行

    我的版本是2019.1里面没有了Use soft wrap in editor 所以在这里新加上*.php;*.html,并且在前面选上打勾就可以了,其余类似编辑器使用类似的方法