切实解决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连接掉线检测的更多相关文章
- TCP连接有效性检测方法
在写TCP服务的时候经常需要面对的问题就是如何知道一个TCP连接当前是否有效,但这个问题对很多初入门的同学来说是很困惑的,主要原因是当对方关闭连接后,另一方无法有效的知道:对于同步操作来说可以通过设置 ...
- corefx 源码学习:SqlClient 是如何同步建立 Socket 连接的
在昨天的技术周会上发现 EnyimMemcached 中建立 Socket 连接的代码有问题,今天坐车的时候在手机上阅读 .net core 2.2 的 SqlClient 中同步建立 Socket ...
- java socket 判断Socket连接失效
要判断socket连接链路是否可用时,不能通过socket.isClosed() 和 socket.isConnected() 方法判断,要通过心跳包 socket.sendUrgentData(0x ...
- 构建简单的socket连接池
一开始,选用Vector<E>来存放连接.由于这个容器不是并发安全的,于是,每个方法都加一个synchronized来保持并发时的同步操作,并发效率很差,果断放弃.空余时间研究了下多线程的 ...
- hadoop单线程实现server多socket连接读取数据原理分析
一.问题引出. Hadoop 的Server 采用了Java 的NIO,这样的话就仅需要为每一个socket 连接建立一个线程,读取socket 上的数据.在Server 中,只需要一个线程,就可以a ...
- Niagara解决设备连接应用的软件框架平台技术。
Niagara 是Tridium公司所研发的设计用于解决设备连接应用的软件框架平台技术. Niagara是一种应用框架,或者说是软件框架,特别设计用于应对智能设备所带来的各种挑战,包括设备连接到企业级 ...
- 解决Socket粘包问题——C#代码
解决Socket粘包问题——C#代码 前天晚上,曾经的一个同事问我socket发送消息如果太频繁接收方就会有消息重叠,因为当时在外面,没有多加思考 第一反应还以为是多线程导致的数据不同步导致的,让他加 ...
- MySQL连接问题【如何解决MySQL连接超时关闭】
--MySQL连接问题[如何解决MySQL连接超时关闭] ------------------------------------------------转载 最近做网站有一个站要用到WEB网页采集器 ...
- 怎样实时判断socket连接状态?
对端正常close socket,或者进程退出(正常退出或崩溃),对端系统正常关闭 这种情况下,协议栈会走正常的关闭状态转移,使用epoll的话,一般要判断如下几个情况 处理可读事件时,在循环read ...
随机推荐
- 几个方便的基于es 的开源文档索引系统
Apache Tika 比较有名的内容提取工具 FsCrawler 使用java 开发,内部使用了Tika Ambar nodejs,python应用开发,轻量,支持基于docker 的快速部署,同时 ...
- Ubuntu 下面手动安装 Redis
1.下载 wget http://download.redis.io/releases/redis-2.8.17.tar.gz .tar.gz cd redis- make 2.复制文件到bin目录 ...
- 初识QuartusII 9.0(破解,半加器的仿真,综合:下)
完成波形的随机设置(A,B任意给定高低电平即可,只是当作测试信号),选择任务栏Assignments[Setings],设置Simulation mode为functional,其余保持不变点击ok. ...
- firefox设置
如果长期使用linux(我常使用的是fedora)的朋友,就会知道,默认情况下,只要是这台linux再内网,开机几个小时后就无法再访问 google 和webqq 这些网站了并且打开一些网站也是要话上 ...
- 【一起来烧脑】入门ES6体系
为什么要学习ES6 掌握ES3.ES5.ES6的联系和区别 快速入门ES6 学会快速构建ES6的编译环境 学习ES6: 常量 作用域 箭头函数 默认参数 对象代理 git git clone http ...
- Sudoku(简单DFS)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5547 数据比较少,直接暴力DFS,检验成立情况即可 AC代码:但是不知道为什么用scanf,print ...
- Linux使用logrotate定时分割日志
1.分割nginx日志vim /etc/logrotate.d/nginx/var/log/nginx/*log { create 0644 nginx nginx rotate 10 missing ...
- TCP四路挥手问题:
1.不管被动和主动,只要发送Fin分节就关闭此端应用层.那么挥手时S接到Fin,此刻C已经关闭应用层,那么S再发送消息岂不是无用,浪费网络资源?
- go type别名和定义类型区别
package main import ( "fmt" ) type person struct { age int name string } func (p person)te ...
- python定制后处理云图
用后处理软件处理的云图会出现这样或那样的不满意,其实我们可以将求解数据导出以后,借助python定制云图. 我们以fluent为例 求解完成之后,我们将我们需要做云图的物理量以ASCII导出 如下的p ...