一、网上常用方法
1、当Socket.Conneted == false时,调用如下函数进行判断

点击(此处)折叠或打开

  1. /// <summary>
  2. /// 当socket.connected为false时,进一步确定下当前连接状态
  3. /// </summary>
  4. /// <returns></returns>
  5. private bool IsSocketConnected()
  6. {
  7. #region remarks
  8. /********************************************************************************************
  9. * 当Socket.Conneted为false时, 如果您需要确定连接的当前状态,请进行非阻塞、零字节的 Send 调用。
  10. * 如果该调用成功返回或引发 WAEWOULDBLOCK 错误代码 (10035),则该套接字仍然处于连接状态;
  11. * 否则,该套接字不再处于连接状态。
  12. * 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
  13. ********************************************************************************************/
  14. #endregion
  15. #region 过程
  16. // This is how you can determine whether a socket is still connected.
  17. bool connectState = true;
  18. bool blockingState = socket.Blocking;
  19. try
  20. {
  21. byte[] tmp = new byte[1];
  22. socket.Blocking = false;
  23. socket.Send(tmp, 0, 0);
  24. //Console.WriteLine("Connected!");
  25. connectState = true; //若Send错误会跳去执行catch体,而不会执行其try体里其之后的代码
  26. }
  27. catch (SocketException e)
  28. {
  29. // 10035 == WSAEWOULDBLOCK
  30. if (e.NativeErrorCode.Equals(10035))
  31. {
  32. //Console.WriteLine("Still Connected, but the Send would block");
  33. connectState = true;
  34. }
  35. else
  36. {
  37. //Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
  38. connectState = false;
  39. }
  40. }
  41. finally
  42. {
  43. socket.Blocking = blockingState;
  44. }
  45. //Console.WriteLine("Connected: {0}", client.Connected);
  46. return connectState;
  47. #endregion
  48. }

2、根据socket.poll判断

点击(此处)折叠或打开

  1. /// <summary>
  2. /// 另一种判断connected的方法,但未检测对端网线断开或ungraceful的情况
  3. /// </summary>
  4. /// <param name="s"></param>
  5. /// <returns></returns>
  6. static bool IsSocketConnected(Socket s)
  7. {
  8. #region remarks
  9. /* As zendar wrote, it is nice to use the Socket.Poll and Socket.Available, but you need to take into conside                ration
  10. * that the socket might not have been initialized in the first place.
  11. * This is the last (I believe) piece of information and it is supplied by the Socket.Connected property.
  12. * The revised version of the method would looks something like this:
  13. * from:http://stackoverflow.com/questions/2661764/how-to-check-if-a- socket-is-connected-disconnected-in-c */
  14. #endregion
  15. #region 过程
  16. return !((s.Poll(1000, SelectMode.SelectRead) && (s.Available == 0)) || !s.Connected);
  17. /* The long, but simpler-to-understand version:
  18. bool part1 = s.Poll(1000, SelectMode.SelectRead);
  19. bool part2 = (s.Available == 0);
  20. if ((part1 && part2 ) || !s.Connected)
  21. return false;
  22. else
  23. return true;
  24. */
  25. #endregion
  26. }

总结:--1--此两种方法出处可在函数体中的remark中找到链接
         --2--此两种方法适用于对端正常关闭socket下的本地socket状态检测,在非正常关闭如断电、拔网线的情况下不起作用
               因为Socket.Conneted存在bug,详见.Net Bugs

二、支持物理断线重连功能的类

        利用BeginReceive + KeepAlive实现物理断线重连,初步测验了一下,正常。(部分代码参考帖子#26blog在C#中利用keep-alive处理socket网络异常断开)
        Keep-Alive机制的介绍请看TCP Keepalive HOWTO
        以此备忘,同时希望能帮助到有需要的同学。

点击(此处)折叠或打开

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Net.Sockets;
  6. using System.Net;
  7. using System.Threading;
  8. namespace MySocket
  9. {
  10. public class Socket_wrapper
  11. {
  12. //委托
  13. private delegate void delSocketDataArrival(byte[] data);
  14. static delSocketDataArrival socketDataArrival = socketDataArrivalHandler;
  15. private delegate void delSocketDisconnected();
  16. static delSocketDisconnected socketDisconnected = socketDisconnectedHandler;
  17. public static Socket theSocket = null;
  18. private static string remoteHost = "192.168.1.71";
  19. private static int remotePort = 6666;
  20. private static String SockErrorStr = null;
  21. private static ManualResetEvent TimeoutObject = new ManualResetEvent(false);
  22. private static Boolean IsconnectSuccess = false; //异步连接情况,由异步连接回调函数置位
  23. private static object lockObj_IsConnectSuccess = new object();
  24. /// <summary>
  25. /// 构造函数
  26. /// </summary>
  27. /// <param name="strIp"></param>
  28. /// <param name="iPort"></param>
  29. public Socket_wrapper(string strIp, int iPort)
  30. {
  31. remoteHost = strIp;
  32. remotePort = iPort;
  33. }
  34. /// <summary>
  35. /// 设置心跳
  36. /// </summary>
  37. private static void SetXinTiao()
  38. {
  39. //byte[] inValue = new byte[] { 1, 0, 0, 0, 0x20, 0x4e, 0, 0, 0xd0, 0x07, 0, 0 };// 首次探测时间20 秒, 间隔侦测时间2 秒
  40. byte[] inValue = new byte[] { 1, 0, 0, 0, 0x88, 0x13, 0, 0, 0xd0, 0x07, 0, 0 };// 首次探测时间5 秒, 间隔侦测时间2 秒
  41. theSocket.IOControl(IOControlCode.KeepAliveValues, inValue, null);
  42. }
  43. /// <summary>
  44. /// 创建套接字+异步连接函数
  45. /// </summary>
  46. /// <returns></returns>
  47. private static bool socket_create_connect()
  48. {
  49. IPAddress ipAddress = IPAddress.Parse(remoteHost);
  50. IPEndPoint remoteEP = new IPEndPoint(ipAddress, remotePort);
  51. theSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  52. theSocket.SendTimeout = 1000;
  53. SetXinTiao();//设置心跳参数
  54. #region 异步连接代码
  55. TimeoutObject.Reset(); //复位timeout事件
  56. try
  57. {
  58. theSocket.BeginConnect(remoteEP, connectedCallback, theSocket);
  59. }
  60. catch (Exception err)
  61. {
  62. SockErrorStr = err.ToString();
  63. return false;
  64. }
  65. if (TimeoutObject.WaitOne(10000, false))//直到timeout,或者TimeoutObject.set()
  66. {
  67. if (IsconnectSuccess)
  68. {
  69. return true;
  70. }
  71. else
  72. {
  73. return false;
  74. }
  75. }
  76. else
  77. {
  78. SockErrorStr = "Time Out";
  79. return false;
  80. }
  81. #endregion
  82. }
  83. /// <summary>
  84. /// 同步receive函数
  85. /// </summary>
  86. /// <param name="readBuffer"></param>
  87. /// <returns></returns>
  88. public string socket_receive(byte[] readBuffer)
  89. {
  90. try
  91. {
  92. if (theSocket == null)
  93. {
  94. socket_create_connect();
  95. }
  96. else if (!theSocket.Connected)
  97. {
  98. if (!IsSocketConnected())
  99. Reconnect();
  100. }
  101. int bytesRec = theSocket.Receive(readBuffer);
  102. if (bytesRec == 0)
  103. {
  104. //warning 0 bytes received
  105. }
  106. return Encoding.ASCII.GetString(readBuffer, 0, bytesRec);
  107. }
  108. catch (SocketException se)
  109. {
  110. //print se.ErrorCode
  111. throw;
  112. }
  113. }
  114. /// <summary>
  115. /// 同步send函数
  116. /// </summary>
  117. /// <param name="sendMessage"></param>
  118. /// <returns></returns>
  119. public bool socket_send(string sendMessage)
  120. {
  121. if (checkSocketState())
  122. {
  123. return SendData(sendMessage);
  124. }
  125. return false;
  126. }
  127. /// <summary>
  128. /// 断线重连函数
  129. /// </summary>
  130. /// <returns></returns>
  131. private static bool Reconnect()
  132. {
  133. //关闭socket
  134. theSocket.Shutdown(SocketShutdown.Both);
  135. theSocket.Disconnect(true);
  136. IsconnectSuccess = false;
  137. theSocket.Close();
  138. //创建socket
  139. return socket_create_connect();
  140. }
  141. /// <summary>
  142. /// 当socket.connected为false时,进一步确定下当前连接状态
  143. /// </summary>
  144. /// <returns></returns>
  145. private bool IsSocketConnected()
  146. {
  147. #region remarks
  148. /********************************************************************************************
  149. * 当Socket.Conneted为false时, 如果您需要确定连接的当前状态,请进行非阻塞、零字节的 Send 调用。
  150. * 如果该调用成功返回或引发 WAEWOULDBLOCK 错误代码 (10035),则该套接字仍然处于连接状态;
  151. * 否则,该套接字不再处于连接状态。
  152. * 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
  153. ********************************************************************************************/
  154. #endregion
  155. #region 过程
  156. // This is how you can determine whether a socket is still connected.
  157. bool connectState = true;
  158. bool blockingState = theSocket.Blocking;
  159. try
  160. {
  161. byte[] tmp = new byte[1];
  162. theSocket.Blocking = false;
  163. theSocket.Send(tmp, 0, 0);
  164. //Console.WriteLine("Connected!");
  165. connectState = true; //若Send错误会跳去执行catch体,而不会执行其try体里其之后的代码
  166. }
  167. catch (SocketException e)
  168. {
  169. // 10035 == WSAEWOULDBLOCK
  170. if (e.NativeErrorCode.Equals(10035))
  171. {
  172. //Console.WriteLine("Still Connected, but the Send would block");
  173. connectState = true;
  174. }
  175. else
  176. {
  177. //Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
  178. connectState = false;
  179. }
  180. }
  181. finally
  182. {
  183. theSocket.Blocking = blockingState;
  184. }
  185. //Console.WriteLine("Connected: {0}", client.Connected);
  186. return connectState;
  187. #endregion
  188. }
  189. /// <summary>
  190. /// 另一种判断connected的方法,但未检测对端网线断开或ungraceful的情况
  191. /// </summary>
  192. /// <param name="s"></param>
  193. /// <returns></returns>
  194. public static bool IsSocketConnected(Socket s)
  195. {
  196. #region remarks
  197. /* As zendar wrote, it is nice to use the Socket.Poll and Socket.Available, but you need to take into consideration
  198. * that the socket might not have been initialized in the first place.
  199. * This is the last (I believe) piece of information and it is supplied by the Socket.Connected property.
  200. * The revised version of the method would looks something like this:
  201. * from:http://stackoverflow.com/questions/2661764/how-to-check-if-a- socket-is-connected-disconnected-in-c */
  202. #endregion
  203. #region 过程
  204. if (s == null)
  205. return false;
  206. return !((s.Poll(1000, SelectMode.SelectRead) && (s.Available == 0)) || !s.Connected);
  207. /* The long, but simpler-to-understand version:
  208. bool part1 = s.Poll(1000, SelectMode.SelectRead);
  209. bool part2 = (s.Available == 0);
  210. if ((part1 && part2 ) || !s.Connected)
  211. return false;
  212. else
  213. return true;
  214. */
  215. #endregion
  216. }
  217. /// <summary>
  218. /// 异步连接回调函数
  219. /// </summary>
  220. /// <param name="iar"></param>
  221. static void connectedCallback(IAsyncResult iar)
  222. {
  223. #region <remarks>
  224. /// 1、置位IsconnectSuccess
  225. #endregion </remarks>
  226. lock (lockObj_IsConnectSuccess)
  227. {
  228. Socket client = (Socket)iar.AsyncState;
  229. try
  230. {
  231. client.EndConnect(iar);
  232. IsconnectSuccess = true;
  233. StartKeepAlive(); //开始KeppAlive检测
  234. }
  235. catch (Exception e)
  236. {
  237. //Console.WriteLine(e.ToString());
  238. SockErrorStr = e.ToString();
  239. IsconnectSuccess = false;
  240. }
  241. finally
  242. {
  243. TimeoutObject.Set();
  244. }
  245. }
  246. }
  247. /// <summary>
  248. /// 开始KeepAlive检测函数
  249. /// </summary>
  250. private static void StartKeepAlive()
  251. {
  252. theSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(OnReceiveCallback), theSocket);
  253. }
  254. /// <summary>
  255. /// BeginReceive回调函数
  256. /// </summary>
  257. static byte[] buffer = new byte[1024];
  258. private static void OnReceiveCallback(IAsyncResult ar)
  259. {
  260. try
  261. {
  262. Socket peerSock = (Socket)ar.AsyncState;
  263. int BytesRead = peerSock.EndReceive(ar);
  264. if (BytesRead > 0)
  265. {
  266. byte[] tmp = new byte[BytesRead];
  267. Array.ConstrainedCopy(buffer, 0, tmp, 0, BytesRead);
  268. if (socketDataArrival != null)
  269. {
  270. socketDataArrival(tmp);
  271. }
  272. }
  273. else//对端gracefully关闭一个连接
  274. {
  275. if (theSocket.Connected)//上次socket的状态
  276. {
  277. if (socketDisconnected != null)
  278. {
  279. //1-重连
  280. socketDisconnected();
  281. //2-退出,不再执行BeginReceive
  282. return;
  283. }
  284. }
  285. }
  286. //此处buffer似乎要清空--待实现 zq
  287. theSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(OnReceiveCallback), theSocket);
  288. }
  289. catch (Exception ex)
  290. {
  291. if (socketDisconnected != null)
  292. {
  293. socketDisconnected(); //Keepalive检测网线断开引发的异常在这里捕获
  294. return;
  295. }
  296. }
  297. }
  298. /// <summary>
  299. /// 异步收到消息处理器
  300. /// </summary>
  301. /// <param name="data"></param>
  302. private static void socketDataArrivalHandler(byte[] data)
  303. {
  304. }
  305. /// <summary>
  306. /// socket由于连接中断(软/硬中断)的后续工作处理器
  307. /// </summary>
  308. private static void socketDisconnectedHandler()
  309. {
  310. Reconnect();
  311. }
  312. /// <summary>
  313. /// 检测socket的状态
  314. /// </summary>
  315. /// <returns></returns>
  316. public static bool checkSocketState()
  317. {
  318. try
  319. {
  320. if (theSocket == null)
  321. {
  322. return socket_create_connect();
  323. }
  324. else if (IsconnectSuccess)
  325. {
  326. return true;
  327. }
  328. else//已创建套接字,但未connected
  329. {
  330. #region 异步连接代码
  331. TimeoutObject.Reset(); //复位timeout事件
  332. try
  333. {
  334. IPAddress ipAddress = IPAddress.Parse(remoteHost);
  335. IPEndPoint remoteEP = new IPEndPoint(ipAddress, remotePort);
  336. theSocket.BeginConnect(remoteEP, connectedCallback, theSocket);
  337. SetXinTiao();//设置心跳参数
  338. }
  339. catch (Exception err)
  340. {
  341. SockErrorStr = err.ToString();
  342. return false;
  343. }
  344. if (TimeoutObject.WaitOne(2000, false))//直到timeout,或者TimeoutObject.set()
  345. {
  346. if (IsconnectSuccess)
  347. {
  348. return true;
  349. }
  350. else
  351. {
  352. return false;
  353. }
  354. }
  355. else
  356. {
  357. SockErrorStr = "Time Out";
  358. return false;
  359. }
  360. #endregion
  361. }
  362. }
  363. catch (SocketException se)
  364. {
  365. SockErrorStr = se.ToString();
  366. return false;
  367. }
  368. }
  369. /// <summary>
  370. /// 同步发送
  371. /// </summary>
  372. /// <param name="dataStr"></param>
  373. /// <returns></returns>
  374. public static bool SendData(string dataStr)
  375. {
  376. bool result = false;
  377. if (dataStr == null || dataStr.Length < 0)
  378. return result;
  379. try
  380. {
  381. byte[] cmd = Encoding.Default.GetBytes(dataStr);
  382. int n = theSocket.Send(cmd);
  383. if (n < 1)
  384. result = false;
  385. }
  386. catch (Exception ee)
  387. {
  388. SockErrorStr = ee.ToString();
  389. result = false;
  390. }
  391. return result;
  392. }
  393. }
  394. }
  395. 参考
  396. https://www.cnblogs.com/MRRAOBX/articles/3601856.html

socket tcp断线重连的更多相关文章

  1. 关于socket tcp 断线重连

    这个问题困扰过我几次,都没有来得及研究,今天研究一下. 首先写一个最简易的socket tcp程序,连接成功后再关闭服务器然后再用客户端各种操作看是什么情况 测试表明 (1)客户端已经连接,当服务端关 ...

  2. Socket实现断线重连

    客户端维护一个线程安全的待发送信息队列   开启死循环   判断Socket = null   调用Socket的sendUrgentData(0xFF)发送1个字节的心跳包   捕捉到连接异常后就关 ...

  3. TCP断线重连

    struct sockaddr_in TempSadd; TempSadd.sin_family = AF_INET; TempSadd.sin_port = htons(m_ServerPort); ...

  4. socket 断线重连

    send发送数据时,发送失败,进行如下重连处理: ) < )//serbuf中有数据可以发送才会执行这条语句 { printf("serial to tcp send msg erro ...

  5. C#之Socket断线重连

    一.网上常用方法 1.当Socket.Conneted == false时,调用如下函数进行判断 /// /// 当socket.connected为false时,进一步确定下当前连接状态 /// / ...

  6. 发现电脑上装着liteide,就用golang做一个TCP通讯测试(支持先启动client端和断线重连)

    1.参考https://www.cnblogs.com/yin5th/p/9274495.html server端 main.go package main import ( "fmt&qu ...

  7. android java socket断线重连

    android java socket断线重连 thread = new Thread(new Runnable() { @Override public void run() { while (tr ...

  8. 基于TCP通信的客户端断线重连

    转载:http://www.cnblogs.com/networkcomms/p/4304362.html 源码下载 在CS程序中,断线重连应该是一个常见的功能. 此处的断线重连主要指的是服务器端因为 ...

  9. netty4 断线重连

    转载:http://www.tuicool.com/articles/B7RzMbY 一 实现心跳检测 原理:当服务端每隔一段时间就会向客户端发送心跳包,客户端收到心跳包后同样也会回一个心跳包给服务端 ...

  10. 浅谈IM软件client的断线重连、心跳和长在线

    版权声明:原创文章,未经博主同意禁止转载.欢迎点击头像上方"郭晓东的专栏"查看专栏 https://blog.csdn.net/hherima/article/details/27 ...

随机推荐

  1. 将Mybatis引入Spring Boot项目连接数据库操作

    将Mybatis引入Spring Boot项目连接数据库操作 一,首先,在pom.xml引入Mybatis插件 加入Maven依赖代码即可快速引入Mybatis 2.0.0: <!--Mybat ...

  2. MySQL系统命令

    原文链接:https://blog.liuzijian.com/post/34b3b940-c053-9d75-06e2-07a2e7aeedc3.html 登录命令 mysql -h 主机 -P 端 ...

  3. Ubuntu20.04配置CuckooSandbox环境

    Ubuntu20.04配置CuckooSandbox环境 因为最近要做恶意软件分析,阅读论文发现动态分析的效果普遍比静态分析的效果要好一些,所以需要搭建一个动态分析的环境,查阅资料发现Cuckoo S ...

  4. 开发者新选择:用DeepSeek实现Cursor级智能编程的免费方案

    前言 去年下半年 cursor 非常火,让很多一行代码都不懂的小白,也可以做自己的网站和搭 App,当时一下子就引爆了独立开发的热潮. 不过每月20dollar的价格也不算便宜,这时候可以使用 cli ...

  5. HTML 基本骨架

    HTML 基本骨架 HTML5的骨架是构建HTML5页面的基础结构,它主要由以下几个部分组成: <!DOCTYPE html> <html> <head> < ...

  6. Kali Linux 安装教程

    Kali Linux 安装教程 下载镜像文件 Kali官网下载 访问Kali官网(https://www.kali.org/ ),根据下图所示进行下载 清华大学开源软件镜像站下载 访问清华大学开源软件 ...

  7. Q:linux(群晖)修改网卡速率

    问题:群晖速度莫名其妙变成了1MB/s左右,查看网络状态 网卡配置变成 全双工10Mb/s 解决方法 首先开启ssh登录权限 1.控制面板 – 终端机和SNMP里,开启SSH功能. 2.通过ssh连接 ...

  8. mac安装spark

    一.基础信息 spark版本:spark-3.1.3-bin-hadoop3.2 hadoop版本:hadoop-3.2.1 scala版本:scala-2.11.12  建议3.12版本 下载地址: ...

  9. FLink16--计数窗口--CountWindiwApp

    一.依赖 https://www.cnblogs.com/robots2/p/16048648.html 二.代码 概念:窗口来多少条计算一次,存在滚动和滑动两种情况 package net.xdcl ...

  10. Luogu P4588 数学运算 题解 [ 绿 ] [ 线段树 ]

    Luogu P4588 数学运算. 虽然是一个很典的题,但里面的思想还是比较值得记录的. 假做法 一开始看到此题还以为是乘法逆元的模板题,但看到 \(m\) 与 \(M\) 不互质,就知道这种做法是假 ...