原文:切实解决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. leetcode解题报告(28):Remove Linked List Elements

    描述 Remove all elements from a linked list of integers that have value val. Example Given: 1 --> 2 ...

  2. leetcode解题报告(26):Add Binary

    描述 Given two binary strings, return their sum (also a binary string). For example, a = "11" ...

  3. Poj 1743 Musical Theme(后缀数组+二分答案)

    Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 28435 Accepted: 9604 Descri ...

  4. ROS里程计

    gmapping导航建图包里建图需要里程计信息,且导航也需要. 整个移动机器人的控制结构如下图所示,其中base_controller节点将订阅的cmd_vel信息通过串口或其它通信接口发送给下位机( ...

  5. python定制后处理云图

    用后处理软件处理的云图会出现这样或那样的不满意,其实我们可以将求解数据导出以后,借助python定制云图. 我们以fluent为例 求解完成之后,我们将我们需要做云图的物理量以ASCII导出 如下的p ...

  6. Open vSwitch系列实验(三):Open vSwitch的VxLAN隧道网络实验

    1 实验目的 该实验通过Open vSwitch构建Overlay的VxLAN网络,更直观的展现VxLAN的优势.在实验过程中,可以了解如何建立VxLAN隧道并进行配置,并实现相同网段和不同网段之间的 ...

  7. 关于Delphi中二维数组赋初始值

    dctb:array[1..2,1..38] of Single=((0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ...

  8. Word 软回车和硬回车

    网页上复制一大段内容,会发现很多向下的箭头,这种叫软回车,要如何批量替换成常见的硬回车呢?   工具/原料   word文档 方法/步骤   1 先认识这种向下的箭头,这种回车形式叫软回车,按shif ...

  9. SonarQube Detection of Injection Flaws in Java, C#, PHP

    Code Quality Tools Review: Sonar, PMD, Findbugs and Checkstyle Sonar CheckStyle, FindBugs and PMD - ...

  10. Tomcat connection & session timeout settings

    # connection timeout for globle web application cat /home/soft/apache-tomcat-7.0.92/conf/server.xml ...