C# + Socket断线重连

简介: 一、网上常用方法 1、当Socket.Conneted == false时,调用如下函数进行判断 点击(此处)折叠或打开 /// /// 当socket.
一、网上常用方法
1、当Socket.Conneted == false时,调用如下函数进行判断

点击(此处)折叠或打开

  1. ///
  2. /// 当socket.connected为false时,进一步确定下当前连接状态
  3. ///
  4. ///
  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. ///
  2. /// 另一种判断connected的方法,但未检测对端网线断开或ungraceful的情况
  3. ///
  4. ///
  5. ///
  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.         ///
  25.         /// 构造函数
  26.         ///
  27.         ///
  28.         ///
  29.         public Socket_wrapper(string strIp, int iPort)
  30.         {
  31.             remoteHost = strIp;
  32.             remotePort = iPort;
  33.         }

  34.         ///
  35.         /// 设置心跳
  36.         ///
  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.         ///
  44.         /// 创建套接字+异步连接函数
  45.         ///
  46.         ///
  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.         ///
  84.         /// 同步receive函数
  85.         ///
  86.         ///
  87.         ///
  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.         ///
  115.         /// 同步send函数
  116.         ///
  117.         ///
  118.         ///
  119.         public bool socket_send(string sendMessage)
  120.         {
  121.             if (checkSocketState())
  122.             {
  123.                 return SendData(sendMessage);
  124.             }
  125.             return false;
  126.         }

  127.         ///
  128.         /// 断线重连函数
  129.         ///
  130.         ///
  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.         ///
  142.         /// 当socket.connected为false时,进一步确定下当前连接状态
  143.         ///
  144.         ///
  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.         ///
  190.         /// 另一种判断connected的方法,但未检测对端网线断开或ungraceful的情况
  191.         ///
  192.         ///
  193.         ///
  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.         ///
  218.         /// 异步连接回调函数
  219.         ///
  220.         ///
  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.         ///
  248.         /// 开始KeepAlive检测函数
  249.         ///
  250.         private static void StartKeepAlive()
  251.         {
  252.             theSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(OnReceiveCallback), theSocket);
  253.         }

  254.         ///
  255.         /// BeginReceive回调函数
  256.         ///
  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.         ///
  299.         /// 异步收到消息处理器
  300.         ///
  301.         ///
  302.         private static void socketDataArrivalHandler(byte[] data)
  303.         {
  304.         }

  305.         ///
  306.         /// socket由于连接中断(软/硬中断)的后续工作处理器
  307.         ///
  308.         private static void socketDisconnectedHandler()
  309.         {
  310.             Reconnect();
  311.         }

  312.         ///
  313.         /// 检测socket的状态
  314.         ///
  315.         ///
  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.         ///
  370.         /// 同步发送
  371.         ///
  372.         ///
  373.         ///
  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. }

、源码下 http://pan.baidu.com/share/link?shareid=2317450258&uk=2080437611


相关文章
|
数据处理 C# C++
如何使用C#和C++结构体实现Socket通信
如何使用C#和C++结构体实现Socket通信
593 0
|
24天前
|
存储 安全 固态存储
基于C#实现的支持文件传输的Socket聊天室
基于C#实现的支持文件传输的Socket聊天室
157 5
|
12月前
|
C# 开发者
C# 一分钟浅谈:Socket 编程基础
【10月更文挑战第7天】本文介绍了Socket编程的基础知识、基本操作及常见问题,通过C#代码示例详细展示了服务器端和客户端的Socket通信过程,包括创建、绑定、监听、连接、数据收发及关闭等步骤,帮助开发者掌握Socket编程的核心技术和注意事项。
283 3
C# 一分钟浅谈:Socket 编程基础
|
9月前
|
网络协议 C# 开发工具
C#中简单Socket编程
1. 先运行服务器代码。服务器将开始监听指定的IP和端口,等待客户端连接。 1. 然后运行客户端代码。客户端将连接到服务器并发送消息。 1. 服务器接收到消息后,将回应客户端,并在控制台上显示接收到的消息。 1. 客户端接收到服务器的回应消息,并在控制台上显示。
376 15
|
12月前
|
消息中间件 网络协议 C#
C#使用Socket实现分布式事件总线,不依赖第三方MQ
`CodeWF.EventBus.Socket` 是一个轻量级的、基于Socket的分布式事件总线系统,旨在简化分布式架构中的事件通信。它允许进程之间通过发布/订阅模式进行通信,无需依赖外部消息队列服务。
C#使用Socket实现分布式事件总线,不依赖第三方MQ
|
移动开发 监控 网络协议
基于Socket通讯(C#)和WebSocket协议(net)编写的两种聊天功能(文末附源码下载地址)
基于Socket通讯(C#)和WebSocket协议(net)编写的两种聊天功能(文末附源码下载地址)
|
C#
C# 使用Socket对接
C# 使用Socket对接
100 1
|
JSON C# 图形学
【Unity 3D】利用C#、Unity和Socket实现简单的在线聊天室工具(附源码 简单易懂)
【Unity 3D】利用C#、Unity和Socket实现简单的在线聊天室工具(附源码 简单易懂)
681 0
|
网络协议 Unix Linux
【Unity 3D】C#中Socket及TCP三次握手与四次挥手详解(超详细 图文解释)
【Unity 3D】C#中Socket及TCP三次握手与四次挥手详解(超详细 图文解释)
524 0
|
网络协议 安全 API
C# Socket网络编程精华篇
C# Socket网络编程精华篇