c# socket 断线重连

https://blog.csdn.net/thebestleo/article/details/52354126

里面有socket的封装类

但是没有使用的代码,在这里补充一下

服务器端主动断开连接,客户端会抛出异常,并会设置连接状态 IsconnectSuccess 为false,但不会自动重连,所以加了一个timer

Socket_wrapper.remoteHost="127.0.0.1";
            Socket_wrapper.remotePort = 9601;
            Socket_wrapper.checkSocketState();

            timer = new Timer();
            timer.Interval = 30 * 1000;
            timer.Tick += Timer_Tick;
            timer.Start();
private void Timer_Tick(object sender, EventArgs e)
        {
            Socket_wrapper.checkSocketState();
        }

补充:之前为啥没有写 接收服务器端的方法,现在补上

socket封装类,socket换成TcpClient  

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Runtime.InteropServices;

namespace TcpDisconnectDemo
{
    public class Socket_wrapper
    {
        //委托
        public  delegate void delSocketDataArrival(byte[] data);
        public static  delSocketDataArrival socketDataArrival = socketDataArrivalHandler;

        public delegate void delSocketDisconnected();
        public static  delSocketDisconnected socketDisconnected = socketDisconnectedHandler;

        public static TcpClient 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();

        ///

        /// 构造函数
        /// 
        /// 
        /// 
        public Socket_wrapper(string strIp, int iPort)
        {
            remoteHost = strIp;
            remotePort = iPort;
        }
        private static byte[] KeepAliveTime
        {
            get
            {
                uint dummy = 0;
                byte[] inOptionValues = new byte[Marshal.SizeOf(dummy) * 3];
                BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0);
                BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues, Marshal.SizeOf(dummy));
                BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2);
                return inOptionValues;
            }
        }
        ///

        /// 设置心跳
        /// 
        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.Client.IOControl(IOControlCode.KeepAliveValues, KeepAliveTime, null);
        }

        ///

        /// 创建套接字+异步连接函数
        /// 
        /// 
        private static bool socket_create_connect()
        {
            IPAddress ipAddress = IPAddress.Parse(remoteHost);
            IPEndPoint remoteEP = new IPEndPoint(ipAddress, remotePort);
            theSocket = new TcpClient();
            theSocket.SendTimeout = 1000;

            SetXinTiao();//设置心跳参数

            #region 异步连接代码

            TimeoutObject.Reset(); //复位timeout事件
            try
            {
                theSocket.BeginConnect(ipAddress,remotePort, 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
        }

        ///

        /// 同步receive函数
        /// 
        /// 
        /// 
        public string socket_receive(byte[] readBuffer)
        {
            try
            {
                if (theSocket == null)
                {
                    socket_create_connect();
                }
                else if (!theSocket.Connected)
                {
                    if (!IsSocketConnected())
                        Reconnect();
                }

                int bytesRec = theSocket.Client.Receive(readBuffer);

                if (bytesRec == 0)
                {
                    //warning 0 bytes received
                }
                return Encoding.ASCII.GetString(readBuffer, 0, bytesRec);
            }
            catch (SocketException se)
            {
                //print se.ErrorCode
                throw;
            }
        }

        ///

        /// 同步send函数
        /// 
        /// 
        /// 
        public bool socket_send(string sendMessage)
        {
            if (checkSocketState())
            {
                return SendData(sendMessage);
            }
            return false;
        }

        ///

        /// 断线重连函数
        /// 
        /// 
        private static bool Reconnect()
        {
            //关闭socket
            theSocket.Client.Shutdown(SocketShutdown.Both);

            theSocket.Client.Disconnect(true);
            IsconnectSuccess = false;

            theSocket.Close();

            //创建socket
            return socket_create_connect();
        }

        ///

        /// 当socket.connected为false时,进一步确定下当前连接状态
        /// 
        /// 
        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.Client.Blocking;
            try
            {
                byte[] tmp = new byte[1];

                theSocket.Client.Blocking = false;
                theSocket.Client.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.Client.Blocking = blockingState;
            }

            //Console.WriteLine("Connected: {0}", client.Connected);
            return connectState;
            #endregion
        }

        ///

        /// 另一种判断connected的方法,但未检测对端网线断开或ungraceful的情况
        /// 
        /// 
        /// 
        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
        }

        ///

        /// 异步连接回调函数
        /// 
        /// 
        static void connectedCallback(IAsyncResult iar)
        {
            #region <remarks>
            /// 1、置位IsconnectSuccess
            #endregion </remarks>

            lock (lockObj_IsConnectSuccess)
            {
                TcpClient client = (TcpClient)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();
                }
            }
        }

        ///

        /// 开始KeepAlive检测函数
        /// 
        private static void StartKeepAlive()
        {
            theSocket.Client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(OnReceiveCallback), theSocket);
        }

        ///

        /// BeginReceive回调函数
        /// 
        static byte[] buffer = new byte[1024];
        private static void OnReceiveCallback(IAsyncResult ar)
        {
            try
            {
                TcpClient peerSock = (TcpClient)ar.AsyncState;
                int BytesRead = peerSock.Client.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.Client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(OnReceiveCallback), theSocket);
            }
            catch (Exception ex)
            {
                if (socketDisconnected != null)
                {
                    socketDisconnected(); //Keepalive检测网线断开引发的异常在这里捕获
                    return;
                }
            }
        }

        ///

        /// 异步收到消息处理器
        /// 
        /// 
        private static void socketDataArrivalHandler(byte[] data)
        {
        }

        ///

        /// socket由于连接中断(软/硬中断)的后续工作处理器
        /// 
        private static void socketDisconnectedHandler()
        {
            Reconnect();
        }

        ///

        /// 检测socket的状态
        /// 
        /// 
        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.Client.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;
            }
        }


        ///

        /// 同步发送
        /// 
        /// 
        /// 
        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.Client.Send(cmd);
                if (n < 1)
                    result = false;
            }
            catch (Exception ee)
            {
                SockErrorStr = ee.ToString();
                result = false;
            }
            return result;
        }
    }
}

程序调用

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TcpDisconnectDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
     
        }

        Socket_wrapper ssw;
        System.Windows.Forms.Timer timer;
        private void Form1_Load(object sender, EventArgs e)
        {


            ssw = new Socket_wrapper("192.168.83.129", 10000);
            Socket_wrapper.socketDataArrival = Socket_wrapper_socketDataArrival;

            Socket_wrapper.checkSocketState();

            timer = new System.Windows.Forms.Timer();
            timer.Interval = 10 * 1000;
            timer.Tick += Timer_Tick;
            timer.Start();



        }
        private delegate void SetLabelDelegate(string value);


        private void SetText(string value)
        {
            if (this.InvokeRequired)
            {
                SetLabelDelegate d = new SetLabelDelegate(SetText);
                this.Invoke(d, new object[] { value });
            }
            else
            {
                textBox1.Text = value.ToString();
            }
        }

        private void Socket_wrapper_socketDataArrival(byte[] data)
        {
            string ss = Encoding.ASCII.GetString(data, 0, data.Length);
            //Console.WriteLine(ss);
            SetText(ss);
        }



        private void Timer_Tick(object sender, EventArgs e)
        {
            Socket_wrapper.checkSocketState();
        }
    }
}

 

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值