C# + Socket断线重连 整理

Socket 连接异常之"由于目标机器积极拒绝,无法连接(System.Net.Sockets.SocketException:Connection refused)" 

1.如果是采用TCP/udp协议进行连接,检查windows防火墙是否开放相应SocketTCP/udp端口;
  简单的检测方法是关闭windows防火墙后再试;

2.检查防火墙软件是否开放相应SocketTCP/udp端口;
  简单的检测方法是关闭防火墙软件后再试;

3.如果服务器端和客户端均在本机上运行,则将相应的 serverIP="127.0.0.1",serveraddress="127.0.0.1";
服务器端侦听:
 listener = new TcpListener(IPAddress.Parse(serverIP), listenport);
               listener.Start();
客户端与服务器建立连接:
  clientsocket = new TcpClient(serveraddress, serverport);

4.如果服务器运行在局域网或广域网内,则将相应的
serverIP,serveraddress设为本机所在局域网或广域网上的IP;

注意 serverport==listenport;

System.Net.Sockets.SocketException: 向一个无法连接的网络尝试了一个套接字操作(System.Net.Sockets.SocketException:Network is unreachable)

IPAddress ipserver = IPAddress.Parse("192.x.x.x");

//IPAddress ipserver = IPAddress.Parse("127.0.0.1");这个没问题

socket.Connect(ipserver, 4000);

------解决方案--------------------
"192.x.x.x" 不是一个有效的地址
127.0.0.1是回送地址,协议立即返回不进行任何网络传输
代码没有任何问题,你需要检查你所要连接的主机IP地址和端口号,用telnet ip port测试看看是不是能连上远程主机

一、网上常用方法

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 (== 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 (< 1)
  384.                     result = false;
  385.             }
  386.             catch (Exception ee)
  387.             {
  388.                 SockErrorStr = ee.ToString();
  389.                 result = false;
  390.             }
  391.             return result;
  392.         }
  393.     }
  394. }


三、源码下载 Sock_Wrapper.cs_免费高速下载|百度网盘-分享无限制

  • 3
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值