TcpClient.cs 8.1 KB
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Net;
using System.Net.Sockets;
using log4net;
using System.Reflection;

namespace OnlineStore.Common
{
    public class TcpClient
    {
        private static string ServerIp = "";
        private static int ServerPort = 0;
        private System.Timers.Timer ReConnectTimer = null;

        public static readonly ILog LOGGER = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
        public delegate void HandleMessage(string message);

        private Socket m_clientSocket;
        private byte[] m_receiveBuffer = new byte[1024];

        private HandleMessage onReceived;

        /// <summary>
        ///  当前连接状态
        /// </summary> 
        public bool IsConnected()
        {
            if (m_clientSocket == null)
            {
                return false;
            }
            if (m_clientSocket.Connected)
            {
                return true;
            }
            #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 = m_clientSocket.Blocking;
            try
            {
                byte[] tmp = new byte[1];

                m_clientSocket.Blocking = false;
                m_clientSocket.Send(tmp, 0, 0);
                //Console.WriteLine("Connected!");
                connectState = true; //若Send错误会跳去执行catch体,而不会执行其try体里其之后的代码
            }
            catch (SocketException e)
            {
                // 10035 == WSAEWOULDBLOCK
                if (e.NativeErrorCode.Equals(10035))
                {
                    connectState = true;
                }
                else
                {
                    connectState = false;
                }
            }
            finally
            {
                m_clientSocket.Blocking = blockingState;
            }

            //Console.WriteLine("Connected: {0}", client.Connected);
            return connectState;
            #endregion
        }
       /// <summary>
       /// 是否在运行中
       /// </summary>
       /// <returns></returns>
        public bool IsRun()
        {
            return ReConnectTimer.Enabled;
        }
        /// <summary>
        /// 连接服务器
        /// </summary>
        public bool StartConnect(string serverIP, int serverPort, HandleMessage HandleMessage,int ReConnectMs=0)
        {
            m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse(serverIP), serverPort);
            onReceived = HandleMessage;
            ServerIp = serverIP;
            ServerPort = serverPort;
            ReConnectTimer = new System.Timers.Timer();
            ReConnectTimer.Interval = ReConnectMs;
            if (ReConnectMs > 0)
            {
                ReConnectTimer.AutoReset = true;
                ReConnectTimer.Elapsed += ReConnectTimer_Elapsed;
            } 
            try
            {
                m_clientSocket.Connect(remoteEndPoint);
                if (m_clientSocket.Connected)
                {
                    m_clientSocket.BeginReceive(m_receiveBuffer, 0, m_receiveBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);
                    onReceived = HandleMessage;
                    LogUtil.info(LOGGER, "Connect to " + serverIP + ":" + serverPort + " success!");
                    ReConnectTimer.Start();
                    return true;
                }
                else
                { 
                    LogUtil.info(LOGGER, "Connect to " + serverIP + ":" + serverPort + " fail!");
                }
            }
            catch (Exception ex)
            {
                LogUtil.error(LOGGER,"Connect to " + serverIP + ":" + serverPort + " fail!" + ex.ToString(),3);
                m_clientSocket = null;
            }

            ReConnectTimer.Start(); 
            return false;
        }

        private bool isInProcess = false;
        private void ReConnectTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            try
            {
                if (isInProcess)
                {
                    return;
                }
                isInProcess = true;
                if (m_clientSocket != null)
                {
                    if (m_clientSocket.Connected)
                    {
                        isInProcess = false;
                        return;
                    }
                }
                try
                {
                    if (m_clientSocket != null)
                    {
                        m_clientSocket.Close();
                        LogUtil.debug(LOGGER, "Socket closed!");
                    }
                }catch(Exception ex)
                {
                    LogUtil.error("m_clientSocket.Close Error"+ex.ToString());
                }

                m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse(ServerIp), ServerPort);
                m_clientSocket.Connect(remoteEndPoint);
                if (m_clientSocket.Connected)
                {
                    m_clientSocket.BeginReceive(m_receiveBuffer, 0, m_receiveBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);

                    LogUtil.info(LOGGER, "Connect to " + ServerIp + ":" + ServerPort + " success!");
                } 

                isInProcess = false;
            }
            catch (Exception ex)
            {
                isInProcess = false;
                LogUtil.error(LOGGER, "重连处理出错:" + ex.ToString(),9,180);
            }
        } 

        /// <summary>
        /// 断开连接
        /// </summary>
        public void close()
        {
            ReConnectTimer.Stop();
            if (m_clientSocket != null)
            {
                m_clientSocket.Close();
                LogUtil.info(LOGGER,"Socket closed!");
            }
            else
            {
                LogUtil.error(LOGGER,"No socket is running!");
            }
        }

        /// <summary>
        /// 发送信息
        /// </summary>
        public void send(string strSendData)
        {
            byte[] sendBuffer = new byte[1024];
            sendBuffer = Encoding.UTF8.GetBytes(strSendData);

            if (m_clientSocket != null && m_clientSocket.Connected)
            {

                m_clientSocket.Send(sendBuffer);
                LogUtil.debug(LOGGER,"Send >> " + strSendData);
            }
        }

        private void ReceiveCallBack(IAsyncResult ar)
        {
            try
            {
                if (m_clientSocket != null && m_clientSocket.Connected)
                {
                    int REnd = m_clientSocket.EndReceive(ar);
                    string strReceiveData = Encoding.UTF8.GetString(m_receiveBuffer, 0, REnd);
                    onReceived(strReceiveData);
                    m_clientSocket.BeginReceive(m_receiveBuffer, 0, m_receiveBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);
                }
            }
            catch (Exception ex)
            {
                LogUtil.error(LOGGER,"socket received error:" + ex.ToString(),4);
            }
        }
    }
}