C# socket 连接超时代码实现

在写 C# socket 的时候发现 socket 连接无法设置超时时间,需要15s才能超时返回。百度一下发现也没有实现的比较好的代码。

因此,才有了下面这段 socket 连接超时的代码,这段代码已经应用到实际的项目中,并且运行稳定。

如果你有更好的实现方案可以给我留言。

    class Socket2 : IComunication
    {
        static IPEndPoint ipe;

        static byte[] sendBytes = new byte[1400];
        static byte[] recBytes = new byte[1400];

        volatile static Socket socket = null;

        static System.Threading.Timer readTimer = null;
        static int readOverTime;
        static bool ReadOK;
        static System.Threading.Timer connectTimer = null;
        static int connectOverTime;

        public Socket2()
        {
            readTimer = new System.Threading.Timer(OnReadTimeUp, null, Timeout.Infinite, Timeout.Infinite);

            object obj = Global.Config.Read("ReadOverTime");
            if (obj == null || !int.TryParse(obj.ToString(), out readOverTime))
            {
                readOverTime = 3000;
            }

            obj = Global.Config.Read("ConnectOverTime");
            if (obj == null || !int.TryParse(obj.ToString(), out connectOverTime))
            {
                connectOverTime = 3000;
            }
        }


        private static void OnConnectTimeUp(object obj)
        {
            StateObject stateObject = (StateObject)obj;
            lock (connectTimer)
            {
                if (stateObject.socket != null)
                {
                    stateObject.socket.Close();
                    stateObject.socket = null;
                    socket = null;
                }
            }
        }

        private static void OnReadTimeUp(object obj)
        {
            ReadOK = false;
            socket.Close();
        }

        public bool Start()
        {
            try
            {
                if (socket == null)
                {
                    string host = Global.Config.Read("DriverIP").ToString();
                    int port = Convert.ToInt32(Global.Config.Read("DriverPort"));
                    IPAddress ip = IPAddress.Parse(host);
                    ipe = new IPEndPoint(ip, port);

                    socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                    socket.DontFragment = false;
                    socket.ExclusiveAddressUse = true;
                    socket.UseOnlyOverlappedIO = false;
                    socket.SendBufferSize = 1500;
                    socket.ReceiveBufferSize = 1500;
                    socket.ReceiveTimeout = readOverTime;
                    socket.SendTimeout = readOverTime;
                    // 设置连接超时计时器
                    StateObject so = new StateObject();
                    so.socket = socket;

                    //socket.Connect(ipe);
                    connectTimer = new System.Threading.Timer(OnConnectTimeUp, so, Timeout.Infinite, Timeout.Infinite);
                    connectTimer.Change(connectOverTime, Timeout.Infinite);
                    socket.BeginConnect(ipe, new AsyncCallback(ConnectCallback), so);
                    autoEventConnect.WaitOne();
                }
                return true;
            }
            catch (SocketException e)
            {
                Global.log.Debug(e);
                socket.Close();
                socket = null;
                return false;
            }
            catch (Exception e)
            {
                if (socket != null)
                {
                    socket.Close();
                }
                socket = null;
                return false;
            }
        }

        AutoResetEvent autoEventConnect = new AutoResetEvent(false);

        private void ConnectCallback(IAsyncResult ar)
        {
            // Retrieve the socket from the state object.
            StateObject stateObject = (StateObject)ar.AsyncState;
            lock (connectTimer)
            {
                try
                {
                    if (stateObject.socket != null)
                    {
                        // Complete the connection.
                        stateObject.socket.EndConnect(ar);

                        connectTimer.Change(Timeout.Infinite, Timeout.Infinite);
                        connectTimer.Dispose();
                    }
                }
                catch (Exception e)
                {
                    if (stateObject.socket != null)
                    {
                        stateObject.socket.Close();
                    }
                    stateObject.socket = null;
                    stateObject.reciveBuffer = null;
                    stateObject.sendBuffer = null;
                    stateObject = null;
                }
            }
            autoEventConnect.Set();
        }


        public bool Stop()
        {
            if (socket != null)
            {
                socket.Close();
            }
            socket = null;
            return true;
        }

        public bool Write()
        {
            try
            {
                if (socket != null)
                {
                    buildSendBytes();
                    socket.NoDelay = true;
                    int n = socket.Send(sendBytes, sendBytes.Length , SocketFlags.None);
                    if (n != sendBytes.Length)
                    {
                        Global.log.Debug("send error 需要发送的字节数 " + "实际发送的字节数" + sendBytes.Length + ":" +n);
                    }
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception e)
            {
                Global.log.Debug("Error Send");
                Global.log.Debug(e);
                if (socket != null)
                {
                    socket.Close();
                    socket = null;
                }
                return false;
            }
        }

        public bool Read()
        {
            try
            {
                if (socket != null)
                {
                    StateObject so = new StateObject();

                    so.socket = socket;
                    so.reciveBuffer = recBytes;
                    // 设置读超时计时器
                    readTimer.Change(readOverTime, Timeout.Infinite);

                    socket.BeginReceive(recBytes, 0, recBytes.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), so);
                    // 接受完成
                    autoEvent.WaitOne();
                    readTimer.Change(Timeout.Infinite, Timeout.Infinite);
                    buildRecBytes();
                    // 需要添加读超时返回 false
                    if (ReadOK == true)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    return false;
                }
            }
            catch (Exception e)
            {
                Global.log.Debug(e);
                return false;
            }
        }

        AutoResetEvent autoEvent = new AutoResetEvent(false);

        public class StateObject
        {
            public Socket socket = null;
            public byte[] reciveBuffer = null;
            public byte[] sendBuffer = null;
        }

        volatile int bytesRecieved = 0;

        public void ReceiveCallback(IAsyncResult ar)
        {
            StateObject state = null;
            try
            {
                // Retrieve the state object and the client socket 
                // from the asynchronous state object.
                state = (StateObject)ar.AsyncState;

                // Read data from the remote device.
                int bytesRead = state.socket.EndReceive(ar);
                if (bytesRead > 1400)
                {
                    Global.log.Debug("bytesRead > 1400 :" + bytesRead);
                }
                if (bytesRead > 0)
                {
                    bytesRecieved += bytesRead;
                    if (bytesRecieved < recBytes.Length)
                    {
                        state.socket.BeginReceive(state.reciveBuffer, bytesRecieved, state.reciveBuffer.Length - bytesRecieved, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
                    }
                    if (bytesRecieved == recBytes.Length)
                    {
                        bytesRecieved = 0;
                        ReadOK = true;
                        autoEvent.Set();
                    }
                }
                else
                {
                    state.socket.Close();
                    state.socket = null;
                    socket = null;
                    state.reciveBuffer = null;
                    state.sendBuffer = null;
                    state = null;
                    ReadOK = false;
                    autoEvent.Set();
                }

            }
            catch (Exception e)
            {
                Global.log.Debug("Error Recieve");
                Global.log.Debug(e);
                if (state.socket != null)
                {
                    state.socket.Close();
                    state.socket = null;
                    socket = null;
                }

                state.reciveBuffer = null;
                state.sendBuffer = null;
                state = null;
                ReadOK = false;
                autoEvent.Set();
            }
        }

        public bool ReadArray()
        {
            throw new NotImplementedException();
        }

        public bool WriteArray()
        {
            throw new NotImplementedException();
        }
    }