socket tcp断线重连
一、网上常用方法
1、当Socket.Conneted == false时,调用如下函数进行判断
点击(此处)折叠或打开
- /// <summary>
- /// 当socket.connected为false时,进一步确定下当前连接状态
- /// </summary>
- /// <returns></returns>
- private bool IsSocketConnected()
- {
- #region remarks
- /********************************************************************************************
- * 当Socket.Conneted为false时, 如果您需要确定连接的当前状态,请进行非阻塞、零字节的 Send 调用。
- * 如果该调用成功返回或引发 WAEWOULDBLOCK 错误代码 (10035),则该套接字仍然处于连接状态;
- * 否则,该套接字不再处于连接状态。
- * Depending on http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.connected.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2
- ********************************************************************************************/
- #endregion
- #region 过程
- // This is how you can determine whether a socket is still connected.
- bool connectState = true;
- bool blockingState = socket.Blocking;
- try
- {
- byte[] tmp = new byte[1];
- socket.Blocking = false;
- socket.Send(tmp, 0, 0);
- //Console.WriteLine("Connected!");
- connectState = true; //若Send错误会跳去执行catch体,而不会执行其try体里其之后的代码
- }
- catch (SocketException e)
- {
- // 10035 == WSAEWOULDBLOCK
- if (e.NativeErrorCode.Equals(10035))
- {
- //Console.WriteLine("Still Connected, but the Send would block");
- connectState = true;
- }
- else
- {
- //Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
- connectState = false;
- }
- }
- finally
- {
- socket.Blocking = blockingState;
- }
- //Console.WriteLine("Connected: {0}", client.Connected);
- return connectState;
- #endregion
- }
2、根据socket.poll判断
点击(此处)折叠或打开
- /// <summary>
- /// 另一种判断connected的方法,但未检测对端网线断开或ungraceful的情况
- /// </summary>
- /// <param name="s"></param>
- /// <returns></returns>
- static bool IsSocketConnected(Socket s)
- {
- #region remarks
- /* As zendar wrote, it is nice to use the Socket.Poll and Socket.Available, but you need to take into conside ration
- * that the socket might not have been initialized in the first place.
- * This is the last (I believe) piece of information and it is supplied by the Socket.Connected property.
- * The revised version of the method would looks something like this:
- * from:http://stackoverflow.com/questions/2661764/how-to-check-if-a- socket-is-connected-disconnected-in-c */
- #endregion
- #region 过程
- return !((s.Poll(1000, SelectMode.SelectRead) && (s.Available == 0)) || !s.Connected);
- /* The long, but simpler-to-understand version:
- bool part1 = s.Poll(1000, SelectMode.SelectRead);
- bool part2 = (s.Available == 0);
- if ((part1 && part2 ) || !s.Connected)
- return false;
- else
- return true;
- */
- #endregion
- }
总结:--1--此两种方法出处可在函数体中的remark中找到链接
--2--此两种方法适用于对端正常关闭socket下的本地socket状态检测,在非正常关闭如断电、拔网线的情况下不起作用
因为Socket.Conneted存在bug,详见.Net Bugs
二、支持物理断线重连功能的类
利用BeginReceive + KeepAlive实现物理断线重连,初步测验了一下,正常。(部分代码参考帖子#26及blog在C#中利用keep-alive处理socket网络异常断开)
Keep-Alive机制的介绍请看TCP Keepalive HOWTO
以此备忘,同时希望能帮助到有需要的同学。
点击(此处)折叠或打开
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Net.Sockets;
- using System.Net;
- using System.Threading;
- namespace MySocket
- {
- public class Socket_wrapper
- {
- //委托
- private delegate void delSocketDataArrival(byte[] data);
- static delSocketDataArrival socketDataArrival = socketDataArrivalHandler;
- private delegate void delSocketDisconnected();
- static delSocketDisconnected socketDisconnected = socketDisconnectedHandler;
- public static Socket theSocket = null;
- private static string remoteHost = "192.168.1.71";
- private static int remotePort = 6666;
- private static String SockErrorStr = null;
- private static ManualResetEvent TimeoutObject = new ManualResetEvent(false);
- private static Boolean IsconnectSuccess = false; //异步连接情况,由异步连接回调函数置位
- private static object lockObj_IsConnectSuccess = new object();
- /// <summary>
- /// 构造函数
- /// </summary>
- /// <param name="strIp"></param>
- /// <param name="iPort"></param>
- public Socket_wrapper(string strIp, int iPort)
- {
- remoteHost = strIp;
- remotePort = iPort;
- }
- /// <summary>
- /// 设置心跳
- /// </summary>
- private static void SetXinTiao()
- {
- //byte[] inValue = new byte[] { 1, 0, 0, 0, 0x20, 0x4e, 0, 0, 0xd0, 0x07, 0, 0 };// 首次探测时间20 秒, 间隔侦测时间2 秒
- byte[] inValue = new byte[] { 1, 0, 0, 0, 0x88, 0x13, 0, 0, 0xd0, 0x07, 0, 0 };// 首次探测时间5 秒, 间隔侦测时间2 秒
- theSocket.IOControl(IOControlCode.KeepAliveValues, inValue, null);
- }
- /// <summary>
- /// 创建套接字+异步连接函数
- /// </summary>
- /// <returns></returns>
- private static bool socket_create_connect()
- {
- IPAddress ipAddress = IPAddress.Parse(remoteHost);
- IPEndPoint remoteEP = new IPEndPoint(ipAddress, remotePort);
- theSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- theSocket.SendTimeout = 1000;
- SetXinTiao();//设置心跳参数
- #region 异步连接代码
- TimeoutObject.Reset(); //复位timeout事件
- try
- {
- theSocket.BeginConnect(remoteEP, connectedCallback, theSocket);
- }
- catch (Exception err)
- {
- SockErrorStr = err.ToString();
- return false;
- }
- if (TimeoutObject.WaitOne(10000, false))//直到timeout,或者TimeoutObject.set()
- {
- if (IsconnectSuccess)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- else
- {
- SockErrorStr = "Time Out";
- return false;
- }
- #endregion
- }
- /// <summary>
- /// 同步receive函数
- /// </summary>
- /// <param name="readBuffer"></param>
- /// <returns></returns>
- public string socket_receive(byte[] readBuffer)
- {
- try
- {
- if (theSocket == null)
- {
- socket_create_connect();
- }
- else if (!theSocket.Connected)
- {
- if (!IsSocketConnected())
- Reconnect();
- }
- int bytesRec = theSocket.Receive(readBuffer);
- if (bytesRec == 0)
- {
- //warning 0 bytes received
- }
- return Encoding.ASCII.GetString(readBuffer, 0, bytesRec);
- }
- catch (SocketException se)
- {
- //print se.ErrorCode
- throw;
- }
- }
- /// <summary>
- /// 同步send函数
- /// </summary>
- /// <param name="sendMessage"></param>
- /// <returns></returns>
- public bool socket_send(string sendMessage)
- {
- if (checkSocketState())
- {
- return SendData(sendMessage);
- }
- return false;
- }
- /// <summary>
- /// 断线重连函数
- /// </summary>
- /// <returns></returns>
- private static bool Reconnect()
- {
- //关闭socket
- theSocket.Shutdown(SocketShutdown.Both);
- theSocket.Disconnect(true);
- IsconnectSuccess = false;
- theSocket.Close();
- //创建socket
- return socket_create_connect();
- }
- /// <summary>
- /// 当socket.connected为false时,进一步确定下当前连接状态
- /// </summary>
- /// <returns></returns>
- private bool IsSocketConnected()
- {
- #region remarks
- /********************************************************************************************
- * 当Socket.Conneted为false时, 如果您需要确定连接的当前状态,请进行非阻塞、零字节的 Send 调用。
- * 如果该调用成功返回或引发 WAEWOULDBLOCK 错误代码 (10035),则该套接字仍然处于连接状态;
- * 否则,该套接字不再处于连接状态。
- * Depending on http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.connected.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2
- ********************************************************************************************/
- #endregion
- #region 过程
- // This is how you can determine whether a socket is still connected.
- bool connectState = true;
- bool blockingState = theSocket.Blocking;
- try
- {
- byte[] tmp = new byte[1];
- theSocket.Blocking = false;
- theSocket.Send(tmp, 0, 0);
- //Console.WriteLine("Connected!");
- connectState = true; //若Send错误会跳去执行catch体,而不会执行其try体里其之后的代码
- }
- catch (SocketException e)
- {
- // 10035 == WSAEWOULDBLOCK
- if (e.NativeErrorCode.Equals(10035))
- {
- //Console.WriteLine("Still Connected, but the Send would block");
- connectState = true;
- }
- else
- {
- //Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
- connectState = false;
- }
- }
- finally
- {
- theSocket.Blocking = blockingState;
- }
- //Console.WriteLine("Connected: {0}", client.Connected);
- return connectState;
- #endregion
- }
- /// <summary>
- /// 另一种判断connected的方法,但未检测对端网线断开或ungraceful的情况
- /// </summary>
- /// <param name="s"></param>
- /// <returns></returns>
- public static bool IsSocketConnected(Socket s)
- {
- #region remarks
- /* As zendar wrote, it is nice to use the Socket.Poll and Socket.Available, but you need to take into consideration
- * that the socket might not have been initialized in the first place.
- * This is the last (I believe) piece of information and it is supplied by the Socket.Connected property.
- * The revised version of the method would looks something like this:
- * from:http://stackoverflow.com/questions/2661764/how-to-check-if-a- socket-is-connected-disconnected-in-c */
- #endregion
- #region 过程
- if (s == null)
- return false;
- return !((s.Poll(1000, SelectMode.SelectRead) && (s.Available == 0)) || !s.Connected);
- /* The long, but simpler-to-understand version:
- bool part1 = s.Poll(1000, SelectMode.SelectRead);
- bool part2 = (s.Available == 0);
- if ((part1 && part2 ) || !s.Connected)
- return false;
- else
- return true;
- */
- #endregion
- }
- /// <summary>
- /// 异步连接回调函数
- /// </summary>
- /// <param name="iar"></param>
- static void connectedCallback(IAsyncResult iar)
- {
- #region <remarks>
- /// 1、置位IsconnectSuccess
- #endregion </remarks>
- lock (lockObj_IsConnectSuccess)
- {
- Socket client = (Socket)iar.AsyncState;
- try
- {
- client.EndConnect(iar);
- IsconnectSuccess = true;
- StartKeepAlive(); //开始KeppAlive检测
- }
- catch (Exception e)
- {
- //Console.WriteLine(e.ToString());
- SockErrorStr = e.ToString();
- IsconnectSuccess = false;
- }
- finally
- {
- TimeoutObject.Set();
- }
- }
- }
- /// <summary>
- /// 开始KeepAlive检测函数
- /// </summary>
- private static void StartKeepAlive()
- {
- theSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(OnReceiveCallback), theSocket);
- }
- /// <summary>
- /// BeginReceive回调函数
- /// </summary>
- static byte[] buffer = new byte[1024];
- private static void OnReceiveCallback(IAsyncResult ar)
- {
- try
- {
- Socket peerSock = (Socket)ar.AsyncState;
- int BytesRead = peerSock.EndReceive(ar);
- if (BytesRead > 0)
- {
- byte[] tmp = new byte[BytesRead];
- Array.ConstrainedCopy(buffer, 0, tmp, 0, BytesRead);
- if (socketDataArrival != null)
- {
- socketDataArrival(tmp);
- }
- }
- else//对端gracefully关闭一个连接
- {
- if (theSocket.Connected)//上次socket的状态
- {
- if (socketDisconnected != null)
- {
- //1-重连
- socketDisconnected();
- //2-退出,不再执行BeginReceive
- return;
- }
- }
- }
- //此处buffer似乎要清空--待实现 zq
- theSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(OnReceiveCallback), theSocket);
- }
- catch (Exception ex)
- {
- if (socketDisconnected != null)
- {
- socketDisconnected(); //Keepalive检测网线断开引发的异常在这里捕获
- return;
- }
- }
- }
- /// <summary>
- /// 异步收到消息处理器
- /// </summary>
- /// <param name="data"></param>
- private static void socketDataArrivalHandler(byte[] data)
- {
- }
- /// <summary>
- /// socket由于连接中断(软/硬中断)的后续工作处理器
- /// </summary>
- private static void socketDisconnectedHandler()
- {
- Reconnect();
- }
- /// <summary>
- /// 检测socket的状态
- /// </summary>
- /// <returns></returns>
- public static bool checkSocketState()
- {
- try
- {
- if (theSocket == null)
- {
- return socket_create_connect();
- }
- else if (IsconnectSuccess)
- {
- return true;
- }
- else//已创建套接字,但未connected
- {
- #region 异步连接代码
- TimeoutObject.Reset(); //复位timeout事件
- try
- {
- IPAddress ipAddress = IPAddress.Parse(remoteHost);
- IPEndPoint remoteEP = new IPEndPoint(ipAddress, remotePort);
- theSocket.BeginConnect(remoteEP, connectedCallback, theSocket);
- SetXinTiao();//设置心跳参数
- }
- catch (Exception err)
- {
- SockErrorStr = err.ToString();
- return false;
- }
- if (TimeoutObject.WaitOne(2000, false))//直到timeout,或者TimeoutObject.set()
- {
- if (IsconnectSuccess)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- else
- {
- SockErrorStr = "Time Out";
- return false;
- }
- #endregion
- }
- }
- catch (SocketException se)
- {
- SockErrorStr = se.ToString();
- return false;
- }
- }
- /// <summary>
- /// 同步发送
- /// </summary>
- /// <param name="dataStr"></param>
- /// <returns></returns>
- public static bool SendData(string dataStr)
- {
- bool result = false;
- if (dataStr == null || dataStr.Length < 0)
- return result;
- try
- {
- byte[] cmd = Encoding.Default.GetBytes(dataStr);
- int n = theSocket.Send(cmd);
- if (n < 1)
- result = false;
- }
- catch (Exception ee)
- {
- SockErrorStr = ee.ToString();
- result = false;
- }
- return result;
- }
- }
- }
- 参考
- https://www.cnblogs.com/MRRAOBX/articles/3601856.html
socket tcp断线重连的更多相关文章
- 关于socket tcp 断线重连
这个问题困扰过我几次,都没有来得及研究,今天研究一下. 首先写一个最简易的socket tcp程序,连接成功后再关闭服务器然后再用客户端各种操作看是什么情况 测试表明 (1)客户端已经连接,当服务端关 ...
- Socket实现断线重连
客户端维护一个线程安全的待发送信息队列 开启死循环 判断Socket = null 调用Socket的sendUrgentData(0xFF)发送1个字节的心跳包 捕捉到连接异常后就关 ...
- TCP断线重连
struct sockaddr_in TempSadd; TempSadd.sin_family = AF_INET; TempSadd.sin_port = htons(m_ServerPort); ...
- socket 断线重连
send发送数据时,发送失败,进行如下重连处理: ) < )//serbuf中有数据可以发送才会执行这条语句 { printf("serial to tcp send msg erro ...
- C#之Socket断线重连
一.网上常用方法 1.当Socket.Conneted == false时,调用如下函数进行判断 /// /// 当socket.connected为false时,进一步确定下当前连接状态 /// / ...
- 发现电脑上装着liteide,就用golang做一个TCP通讯测试(支持先启动client端和断线重连)
1.参考https://www.cnblogs.com/yin5th/p/9274495.html server端 main.go package main import ( "fmt&qu ...
- android java socket断线重连
android java socket断线重连 thread = new Thread(new Runnable() { @Override public void run() { while (tr ...
- 基于TCP通信的客户端断线重连
转载:http://www.cnblogs.com/networkcomms/p/4304362.html 源码下载 在CS程序中,断线重连应该是一个常见的功能. 此处的断线重连主要指的是服务器端因为 ...
- netty4 断线重连
转载:http://www.tuicool.com/articles/B7RzMbY 一 实现心跳检测 原理:当服务端每隔一段时间就会向客户端发送心跳包,客户端收到心跳包后同样也会回一个心跳包给服务端 ...
- 浅谈IM软件client的断线重连、心跳和长在线
版权声明:原创文章,未经博主同意禁止转载.欢迎点击头像上方"郭晓东的专栏"查看专栏 https://blog.csdn.net/hherima/article/details/27 ...
随机推荐
- Idea创建maven项目流程、修改默认配置、及注意事项
这里所演示的环境: windows7+jdk1.7.0_80+tomcat8.5.41+maven3.0.5+idea2017.3.6 1.idea使用指定maven版本 打开idea,使用快捷键ct ...
- shell脚本中的变量
在shell脚本中使用变量显得我们的脚本更加专业更像是一门语言,开个玩笑,变量的作用当然不是为了专业.如果你写了一个长达1000行的shell脚本,并且脚本中出现了某一个命令或者路径几百次.突然你觉得 ...
- 微软宣布更新SymCrypt加密库,新增对PQC算法的支持
转载链接:https://mp.weixin.qq.com/s/aWXzPTWhxFpJVP1s0iwAtw 2024年9月9日,微软(Microsoft)在其博客中宣布,已开始在其开源核心加密库Sy ...
- Synchronized的各场景使用方法(多窗口售票例子接上篇)
同步锁机制:在<Thinking in Java>中,是这么说的:对于并发工作,你需要某种方式来防止两个任务访问相同的资源(其实就是共享资源竞争). 防止这种冲突的方法就是当资源被一个 ...
- PayDay Intermediate
nmap + dirsearch 发现web站点 扫目录 ┌──(root㉿kali)-[/home/ftpuserr] └─# nmap -p- -A 192.168.167.39 Starting ...
- Phi小模型开发教程:C#使用本地模型Phi视觉模型分析图像,实现图片分类、搜索等功能
大家好,我是编程乐趣. 我们都知道,要实现对结构化的数据(文本)搜索是比较容易的,但是对于非结构化的数据,比如图片,视频就没那么简单了. 但是现在有了AI模型,实现图片分类.搜索等功能,就变得容易很多 ...
- uni-app组件 信息列表组件
之前我一直在,要想提高自己的代码质量, 就一定要封装自己的组件, 所以我就尽量使用自己的组件.这样可以提高自己的效率 写组件的好处:减少代码的冗余 封装组件的时候,为了不让子元素的padding, 影 ...
- brew切换数据源为阿里源
# 查看 brew.git 当前源 $ cd "$(brew --repo)" && git remote -v origin https://github.com ...
- Luogu P2468 SDOI2010 粟粟的书架 题解 [ 紫 ] [ 可持久化线段树 ] [ 二分 ] [ 前缀和 ]
粟粟的书架:二合一的缝合题. 前一半测试点 此时是 \(200\times 200\) 的二维问题,首先考虑暴力怎么写,显然是每次询问把查的全扔进大根堆里,然后一直取堆顶直到满足要求或者取空. 那么这 ...
- MybatisPlus - [05] 逻辑删除
题记部分 一.物理删除&逻辑删除 物理删除:delete from table_name where xxx = ?; 逻辑删除:update table_name set deleted = ...