原文:切实解决socket连接掉线检测

版权声明:欢迎转载,但是请保留出处说明 https://blog.csdn.net/lanwilliam/article/details/51698807

新公司在做物联网,要做与modbus设备的通讯服务。在过程中除了研究modbus协议外,最麻烦的就是设备在线状态的检测问题。

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);
}
}

项目内容比较多,并且是公司项目,就不完整贴出来了,相信会对大家有帮助。

切实解决socket连接掉线检测的更多相关文章

  1. TCP连接有效性检测方法

    在写TCP服务的时候经常需要面对的问题就是如何知道一个TCP连接当前是否有效,但这个问题对很多初入门的同学来说是很困惑的,主要原因是当对方关闭连接后,另一方无法有效的知道:对于同步操作来说可以通过设置 ...

  2. corefx 源码学习:SqlClient 是如何同步建立 Socket 连接的

    在昨天的技术周会上发现 EnyimMemcached 中建立 Socket 连接的代码有问题,今天坐车的时候在手机上阅读 .net core 2.2 的 SqlClient 中同步建立 Socket ...

  3. java socket 判断Socket连接失效

    要判断socket连接链路是否可用时,不能通过socket.isClosed() 和 socket.isConnected() 方法判断,要通过心跳包 socket.sendUrgentData(0x ...

  4. 构建简单的socket连接池

    一开始,选用Vector<E>来存放连接.由于这个容器不是并发安全的,于是,每个方法都加一个synchronized来保持并发时的同步操作,并发效率很差,果断放弃.空余时间研究了下多线程的 ...

  5. hadoop单线程实现server多socket连接读取数据原理分析

    一.问题引出. Hadoop 的Server 采用了Java 的NIO,这样的话就仅需要为每一个socket 连接建立一个线程,读取socket 上的数据.在Server 中,只需要一个线程,就可以a ...

  6. Niagara解决设备连接应用的软件框架平台技术。

    Niagara 是Tridium公司所研发的设计用于解决设备连接应用的软件框架平台技术. Niagara是一种应用框架,或者说是软件框架,特别设计用于应对智能设备所带来的各种挑战,包括设备连接到企业级 ...

  7. 解决Socket粘包问题——C#代码

    解决Socket粘包问题——C#代码 前天晚上,曾经的一个同事问我socket发送消息如果太频繁接收方就会有消息重叠,因为当时在外面,没有多加思考 第一反应还以为是多线程导致的数据不同步导致的,让他加 ...

  8. MySQL连接问题【如何解决MySQL连接超时关闭】

    --MySQL连接问题[如何解决MySQL连接超时关闭] ------------------------------------------------转载 最近做网站有一个站要用到WEB网页采集器 ...

  9. 怎样实时判断socket连接状态?

    对端正常close socket,或者进程退出(正常退出或崩溃),对端系统正常关闭 这种情况下,协议栈会走正常的关闭状态转移,使用epoll的话,一般要判断如下几个情况 处理可读事件时,在循环read ...

随机推荐

  1. npm 删除指定的某个包以及再次安装

    npm uninstall xxxx --save-dev //删除包及删除配置项 npm install xxx@version //安装指定版本 npm install //覆盖

  2. 机器学习实战(1)- KNN

    KNN:k近邻算法-在训练样本中找到与待测样本距离相近的N个样本,并用这N个样本中所属概率最大的类别作为待测样本的类别. 算法步骤: 1.对训练中的样本数据的不同属性进行归一化处理. 2.计算待测样本 ...

  3. [WEB安全]SSRF中URL的伪协议

    当我们发现SSRF漏洞后,首先要做的事情就是测试所有可用的URL伪协议 0x01 类型 file:/// dict:// sftp:// ldap:// tftp:// gopher:// file: ...

  4. Linux 搜索查找类指令

    一.find  指令 find 指令将从指定目录向下递归遍历其各子目录,将满足条件的文件或者目录显示在终端. 基本语法 find  [搜索范围]  [选项] 选项说明 -name            ...

  5. ubuntu之路——day10.7 提高模型的表现

    总结一下就是在提升偏差的方面(即贝叶斯最优误差和训练误差的差距) 1.尝试更大更深的网络 2.加入优化算法比如前面提过的momentum.RMSprop.Adam等 3.使用别的神经网络架构比如RNN ...

  6. T-MAX-冲刺总结

    T-MAX-冲刺总结 这个作业属于哪个课程 班级链接 这个作业要求在哪里 作业要求的链接 团队名称 T-MAX 这个作业的目标 冲刺总结 作业的正文 T-MAX-冲刺总结 其他参考文献 面向B站,百度 ...

  7. 在dubbo工程中,使用druid监控

    介绍:在dubbo项目中,使用druid的监控功能 问题:因为,在网上找勒,很多的资料,显示的都是需要在web.xml中配置 <servlet> <servlet-name>D ...

  8. NAXSI means Nginx Anti XSS & SQL Injection. NAXSI is an open-source, high performance, low rules maintenance WAF for NGINX

    nbs-system/naxsi: NAXSI is an open-source, high performance, low rules maintenance WAF for NGINXhttp ...

  9. Java基础 Scanner 使用nextLine接收字符串

        JDK :OpenJDK-11      OS :CentOS 7.6.1810      IDE :Eclipse 2019‑03 typesetting :Markdown   code ...

  10. [转]arcgis for server 10.2 下载及安装

    转自:https://blog.csdn.net/nominior/article/details/80211963 https://blog.csdn.net/mrib/article/detail ...