/********************************************************************
 * *
 * * Copyright (C) 2013-2018 uiskin.cn
 * * 作者： BinGoo QQ：315567586
 * * 请尊重作者劳动成果，请保留以上作者信息，禁止用于商业活动。
 * *
 * * 创建时间：2014-08-05
 * * 说明：ITcpServer服务端组件
 * *
********************************************************************/

using NetWorkHelper.Helper;
using NetWorkHelper.ICommond;
using NetWorkHelper.IModels;
using NetWorkHelper.ITool;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;

namespace NetWorkHelper.TCP
{
    public partial class ITcpServer : Component, IServerBase
    {
        #region 变量

        // 监听Socket
        private Socket _serverSocket = null;

        // 心跳检测线程
        private Thread _tHeartCheck = null;

        //监听IP，为空时监听本机所有IP
        private string _serverIp = "";

        //监听端口
        private int _serverPort = 5000;

        //网络端点
        private IPEndPoint _ipEndPoint = null;

        //是否开启心跳检测
        private bool _isHeartCheck = true;

        //心跳检测间隔
        private int _checkTime = 3000;

        //是否已启动监听
        private bool _isStartListening = false;

        //客户端列表
        private List<IClient> _clientList;

        #endregion 变量

        #region 属性

        /// <summary>
        /// 无IP地址时默认监听本机所有IP
        /// </summary>
        [Description("无IP地址时默认监听本机所有IP")]
        [Category("TCP服务端")]
        public string ServerIp
        {
            get { return _serverIp; }
            set { _serverIp = value; }
        }

        /// <summary>
        /// 本机监听端口
        /// </summary>
        [Description("本机监听端口")]
        [Category("TCP服务端")]
        public int ServerPort
        {
            get { return _serverPort; }
            set { _serverPort = value; }
        }

        /// <summary>
        /// 网络端点,IP+PORT
        /// </summary>
        [Description("网络端点,IP+PORT")]
        [Category("TCP服务端"), Browsable(false)]
        internal IPEndPoint IpEndPoint
        {
            get
            {
                try
                {
                    IPAddress ipAddress = null;
                    if (ServerIp == "")
                        ipAddress = IPAddress.Any;
                    else
                        ipAddress = IPAddress.Parse(CommonMethod.HostnameToIp(ServerIp));
                    _ipEndPoint = new IPEndPoint(ipAddress, ServerPort);
                }
                catch
                {
                }
                return _ipEndPoint;
            }
        }

        /// <summary>
        /// 是否开启心跳检测
        /// </summary>
        [Description("是否开启心跳检测")]
        [Category("TCP服务端")]
        public bool IsHeartCheck
        {
            get { return _isHeartCheck; }
            set { _isHeartCheck = value; }
        }

        /// <summary>
        /// 心跳检测时间,单位：毫秒
        /// </summary>
        [Description("心跳检测时间,单位：毫秒")]
        [Category("TCP服务端")]
        public int CheckTime
        {
            get { return _checkTime; }
            set { _checkTime = value; }
        }

        /// <summary>
        /// 是否已启动监听
        /// </summary>
        [Description("是否已启动监听")]
        [Category("TCP服务端"), Browsable(false)]
        public bool IsStartListening
        {
            get { return _isStartListening; }
            private set { _isStartListening = value; }
        }

        /// <summary>
        /// 客户端列表
        /// </summary>
        [Description("客户端列表")]
        [Category("TCP服务端"), Browsable(false)]
        public List<IClient> ClientSocketList
        {
            get
            {
                if (_clientList == null)
                {
                    _clientList = new List<IClient>();
                }
                return _clientList;
            }
        }

        #endregion 属性

        #region 构造函数

        public ITcpServer()
        {
            InitializeComponent();
        }

        public ITcpServer(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
        }

        #endregion 构造函数

        #region 接口实现方法

        /// <summary>
        /// 开启监听
        /// </summary>
        public void Start()
        {
            if (IsStartListening)
                return;
            StartListen();
        }

        /// <summary>
        /// 启动服务器,没出现异常,则启动成功
        /// </summary>
        private void StartListen()
        {
            IsStartListening = true;
            try
            {
                _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                _serverSocket.Bind(IpEndPoint);
                _serverSocket.Listen(10000);

                TcpServerStateInfo(null, string.Format("服务端Ip:{0},端口:{1}已启动监听", ServerIp, ServerPort), SocketState.StartListening);
                TcpServerGetLog(null, LogType.Server, string.Format("服务端Ip:{0},端口:{1}已启动监听", string.IsNullOrEmpty(ServerIp) ? "本机所有IP" : ServerIp, ServerPort));
                _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);

                if (_tHeartCheck == null)
                {
                    _tHeartCheck = new Thread(new ThreadStart(HeartCheckThread));
                    _tHeartCheck.IsBackground = true;
                    _tHeartCheck.Start();
                }

                IsStartListening = true;
            }
            catch (Exception ex)
            {
                IsStartListening = false;
                TcpServerStateInfo(null, string.Format("服务端Ip:{0},端口:{1}启动监听失败", ServerIp, ServerPort),
                    SocketState.StartListeningError);
                TcpServerGetLog(null, LogType.Server, ex.Message);
            }
        }

        /// <summary>
        /// 停止监听，释放所有资源
        /// </summary>
        public void Stop()
        {
            try
            {
                IsStartListening = false;
                if (_serverSocket != null)
                {
                    _serverSocket.Close();
                }
                _serverSocket = null;

                if (_tHeartCheck != null)
                {
                    _tHeartCheck.Interrupt();
                    _tHeartCheck.Abort();
                    //_tHeartCheck.Join();
                }
                _tHeartCheck = null;
                CloseClient();
                ClientSocketList.Clear();
                TcpServerReturnClientCount(ClientSocketList.Count);
                TcpServerStateInfo(null, string.Format("服务端已停止监听"), SocketState.StopListening);
                TcpServerGetLog(null, LogType.Server, "服务端已停止监听");
            }
            catch (Exception ex)
            {
                TcpServerErrorMsg(string.Format("停止监听时发生错误，错误原因：{0},行号{1}", ex.Message, ex.StackTrace));
            }
        }

        #endregion 接口实现方法

        #region 心跳检测方法模块

        /// <summary>
        /// 心跳检测
        /// </summary>
        private void HeartCheckThread()
        {
            try
            {
                while (IsStartListening)
                {
                    try
                    {
                        Thread.Sleep(CheckTime);

                        if (!IsHeartCheck)
                        {
                            //如果没有开启心跳检测或者没有启动监听则跳过检测
                            continue;
                        }

                        int i = 0;
                        while (i < ClientSocketList.Count)
                        {
                            try
                            {
                                Thread.Sleep(1);
                                if (!IsStartListening)
                                {
                                    break;
                                }
                                byte[] sendHeartbeatData = new byte[0];
                                if (i > ClientSocketList.Count - 1)
                                {
                                    break;
                                }
                                switch (ClientSocketList[i].ClientInfo.HeartCheckType)
                                {
                                    case HeartCheckType.EncodingString:
                                        if (!string.IsNullOrEmpty(ClientSocketList[i].ClientInfo.Heartbeat))
                                        {
                                            sendHeartbeatData =
                                                Encoding.Default.GetBytes(ClientSocketList[i].ClientInfo.Heartbeat);
                                        }
                                        break;

                                    case HeartCheckType.HexString:
                                        sendHeartbeatData =
                                        ConvertStringManager.StringToHexByteArray(
                                            ClientSocketList[i].ClientInfo.Heartbeat);
                                        break;

                                    case HeartCheckType.Byte:
                                        sendHeartbeatData = ClientSocketList[i].ClientInfo.HeartbeatByte;
                                        break;

                                    default:
                                        break;
                                }

                                if (sendHeartbeatData.Length > 0)
                                {
                                    if (i > ClientSocketList.Count - 1)
                                    {
                                        break;
                                    }
                                    if (ClientSocketList[i].ClientStyle == ClientStyle.WebSocket)
                                    {
                                        SendToWebClient(ClientSocketList[i],
                                            Encoding.Default.GetString(sendHeartbeatData));
                                    }
                                    else
                                    {
                                        SendData(ClientSocketList[i], sendHeartbeatData);
                                    }
                                }

                                i++;
                            }
                            catch (Exception ex)
                            {
                                TcpServerErrorMsg(string.Format("心跳检测时发生错误，错误原因：{0},行号{1}", ex.Message, ex.StackTrace));
                                try
                                {
                                    if (ClientSocketList[i].WorkSocket != null)
                                    {
                                        TcpServerOfflineClient(ClientSocketList[i]);
                                        ClientSocketList.Remove(ClientSocketList[i]);
                                        TcpServerReturnClientCount(ClientSocketList.Count);
                                    }
                                }
                                catch (Exception e)
                                {
                                    TcpServerErrorMsg(string.Format("处理心跳检测异常时发生错误，错误原因：{0},行号{1}", ex.Message, e.StackTrace));
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        TcpServerErrorMsg(string.Format("心跳检测异常处理时发生错误，错误原因：{0},行号{1}", ex.Message, ex.StackTrace));
                    }
                }
            }
            catch
            {
            }
        }

        /// <summary>
        /// 手动检测
        /// </summary>
        public void HandCheck()
        {
            int i = 0;
            while (i < ClientSocketList.Count)
            {
                Thread.Sleep(1);

                if (ClientSocketList[i] == null)
                {
                    TcpServerOfflineClient(ClientSocketList[i]);
                    ClientSocketList.RemoveAt(i);
                    TcpServerReturnClientCount(ClientSocketList.Count);
                    continue;
                }
                string sendLoginMsg = string.IsNullOrEmpty(ClientSocketList[i].ClientInfo.Heartbeat) ? "客户端\r\n" : ClientSocketList[i].ClientInfo.Heartbeat;
                try
                {
                    SendData(ClientSocketList[i], Encoding.Default.GetBytes(sendLoginMsg));
                    i++;
                }
                catch (Exception ex)
                {
                    TcpServerErrorMsg(string.Format("手动检测时发生错误，错误原因：{0},行号{1}", ex.Message, ex.StackTrace));
                    try
                    {
                        if (ClientSocketList[i].WorkSocket != null)
                        {
                            TcpServerOfflineClient(ClientSocketList[i]);
                            ClientSocketList.Remove(ClientSocketList[i]);
                            TcpServerReturnClientCount(ClientSocketList.Count);
                        }
                        continue;
                    }
                    catch (Exception e)
                    {
                        TcpServerErrorMsg(string.Format("手动检测异常处理时发生错误，错误原因：{0}", e.Message));
                    }
                }
            }
        }

        #endregion 心跳检测方法模块

        #region Socket相关方法

        /// <summary>
        /// 异步监听当有客户端连接后的回调函数
        /// </summary>
        /// <param name="iar"></param>
        private void AcceptCallback(IAsyncResult iar)
        {
            IClient iClient = null;
            try
            {
                if (_serverSocket != null)
                    _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
            }
            catch (Exception ex)
            {
                TcpServerErrorMsg(string.Format("监听客户端连接状态时发生错误，错误原因：{0},行号{1}", ex.Message, ex.StackTrace));
                Stop();
            }
            try
            {
                if (_serverSocket != null)
                {
                    Socket workSocket = _serverSocket.EndAccept(iar);
                    iClient = new IClient(workSocket);
                    ClientSocketList.Add(iClient);
                    TcpServerStateInfo(iClient, string.Format("<{0}：{1}>---上线", iClient.Ip, iClient.Port), SocketState.ClientOnline);

                    TcpServerGetLog(iClient, LogType.Client, "客户端上线"); //记录
                    TcpServerOnlineClient(iClient);
                    TcpServerReturnClientCount(ClientSocketList.Count);
                    iClient.WorkSocket.BeginReceive(iClient.BufferInfo.ReceivedBuffer, 0, iClient.BufferInfo.ReceivedBuffer.Length, 0, new AsyncCallback(ClientReadCallback), iClient);
                }
            }
            catch (Exception ex)
            {
                ShutdownClient(iClient);
                TcpServerOfflineClient(iClient);
                ClientSocketList.Remove(iClient);
                TcpServerReturnClientCount(ClientSocketList.Count);
                TcpServerErrorMsg(string.Format("监听客户端时发生错误，错误原因：{0},行号{1}", ex.Message, ex.StackTrace));
            }
        }

        /// <summary>
        /// 异步接收数据
        /// </summary>
        /// <param name="ar"></param>
        private void ClientReadCallback(IAsyncResult ar)
        {
            IClient iClient = (IClient)ar.AsyncState;
            try
            {
                int bytesRead = iClient.WorkSocket.EndReceive(ar);
                if (bytesRead > 0)
                {
                    //byte[] haveDate = ReceiveDateOne.DateOneManage(iClient, bytesRead);//接收完成之后对数组进行重置
                    byte[] bytes = new byte[bytesRead];
                    Array.Copy(iClient.BufferInfo.ReceivedBuffer, 0, bytes, 0, bytesRead);
                    string clientRecevieStr = "";

                    #region WebSocket验证

                    //验证websocket握手协议
                    if (iClient != null && iClient.ClientStyle != ClientStyle.WebSocket)
                    {
                        clientRecevieStr = ASCIIEncoding.Default.GetString(iClient.BufferInfo.ReceivedBuffer, 0, bytesRead);
                        //如果客户端不存在则退出检测
                        WebSocketHandShake(iClient, clientRecevieStr, bytes);
                    }
                    if (iClient.ClientStyle == ClientStyle.WebSocket)
                    {
                        string webstr = AnalyticData(bytes, bytes.Length);
                        clientRecevieStr = webstr;
                        bytes = Encoding.Default.GetBytes(clientRecevieStr);
                    }

                    #endregion WebSocket验证

                    TcpServerRecevice(iClient, bytes);
                    TcpServerGetLog(iClient, LogType.ReceviedData, ConvertStringManager.HexByteArrayToString(bytes));
                    iClient.WorkSocket.BeginReceive(iClient.BufferInfo.ReceivedBuffer, 0,
                        iClient.BufferInfo.ReceivedBuffer.Length, 0,
                        new AsyncCallback(ClientReadCallback), iClient);
                }
                else if (bytesRead == 0)
                {
                    //接收数据长度为0时，标示客户单下线
                    if (iClient != null)
                    {
                        ShutdownClient(iClient);
                        TcpServerStateInfo(iClient, string.Format("<{0}：{1}>---下线", iClient.Ip, iClient.Port), SocketState.ClientOnOff);
                        RemoveClient(iClient, "客户端下线");
                        TcpServerOfflineClient(iClient);
                        ClientSocketList.Remove(iClient);
                        TcpServerReturnClientCount(ClientSocketList.Count);
                    }
                }
            }
            catch (Exception ex)
            {
                TcpServerErrorMsg(string.Format("接收客户端数据时发生错误，错误原因：{0},行号{1}", ex.Message, ex.StackTrace));
                int i = ex.Message.IndexOf("远程主机强迫关闭了一个现有的连接");
                if (iClient != null && i != -1)
                {
                    RemoveClient(iClient, ex.Message);
                }
                iClient = null;
            }
        }

        #endregion Socket相关方法

        #region websocket模块

        public void WebSocketHandShake(IClient iClient, string msg, byte[] data)
        {
            #region 网络WebSocket协议握手

            string webkey = GetSecKey(data, data.Length);
            if (!string.IsNullOrEmpty(webkey) && iClient.ClientStyle != ClientStyle.WebSocket)
            {
                byte[] bufferwoshou = PackHandShakeData(webkey);
                if (bufferwoshou.Length > 0)
                {
                    iClient.ClientStyle = ClientStyle.WebSocket;
                    iClient.WorkSocket.Send(bufferwoshou);
                }
            }
            else
            {
            }

            #endregion 网络WebSocket协议握手
        }

        /// <summary>
        /// 解析数据
        /// </summary>
        /// <param name="recBytes"></param>
        /// <param name="recByteLength"></param>
        /// <returns></returns>
        public string AnalyticData(byte[] recBytes, int recByteLength)
        {
            //byte[] bytes = new byte[recByteLength];
            //Array.Copy(recBytes, 0, bytes, 0, recByteLength);
            //return Encoding.Default.GetString(bytes);

            if (recByteLength < 2) { return string.Empty; }

            bool fin = (recBytes[0] & 0x80) == 0x80; // 1bit，1表示最后一帧
            if (!fin)
            {
                return string.Empty;// 超过一帧暂不处理
            }

            bool mask_flag = (recBytes[1] & 0x80) == 0x80; // 是否包含掩码
            if (!mask_flag)
            {
                return string.Empty;// 不包含掩码的暂不处理
            }

            int payload_len = recBytes[1] & 0x7F; // 数据长度

            byte[] masks = new byte[4];
            byte[] payload_data;

            if (payload_len == 126)
            {
                Array.Copy(recBytes, 4, masks, 0, 4);
                payload_len = (UInt16)(recBytes[2] << 8 | recBytes[3]);
                payload_data = new byte[payload_len];
                Array.Copy(recBytes, 8, payload_data, 0, payload_len);
            }
            else if (payload_len == 127)
            {
                Array.Copy(recBytes, 10, masks, 0, 4);
                byte[] uInt64Bytes = new byte[8];
                for (int i = 0; i < 8; i++)
                {
                    uInt64Bytes[i] = recBytes[9 - i];
                }
                UInt64 len = BitConverter.ToUInt64(uInt64Bytes, 0);

                payload_data = new byte[len];
                for (UInt64 i = 0; i < len; i++)
                {
                    payload_data[i] = recBytes[i + 14];
                }
            }
            else
            {
                Array.Copy(recBytes, 2, masks, 0, 4);
                payload_data = new byte[payload_len];
                Array.Copy(recBytes, 6, payload_data, 0, payload_len);
            }

            for (var i = 0; i < payload_len; i++)
            {
                payload_data[i] = (byte)(payload_data[i] ^ masks[i % 4]);
            }

            return Encoding.UTF8.GetString(payload_data);
        }

        /// <summary>
        /// 向客户端发送信息
        /// </summary>
        /// <param name="iClient">客户端</param>
        /// <param name="sendData">发送的数据包</param>
        public void SendToWebClient(IClient iClient, string sendData)
        {
            if (iClient == null)
            {
                return;
            }
            if (!iClient.WorkSocket.Connected)
            {
                return;
            }
            try
            {
                DataFrame dr = new DataFrame(sendData);
                iClient.WorkSocket.Send(dr.GetBytes());
            }
            catch (Exception ex)
            {
                //logger.Log(ex.Message);
            }
        }

        /// <summary>
        /// 打包服务器数据
        /// </summary>
        /// <param name="message">数据</param>
        /// <returns>数据包</returns>
        private byte[] PackData(string message)
        {
            byte[] contentBytes = null;
            byte[] temp = Encoding.UTF8.GetBytes(message);

            if (temp.Length < 126)
            {
                contentBytes = new byte[temp.Length + 2];
                contentBytes[0] = 0x81;
                contentBytes[1] = (byte)temp.Length;
                Array.Copy(temp, 0, contentBytes, 2, temp.Length);
            }
            else if (temp.Length < 0xFFFF)
            {
                contentBytes = new byte[temp.Length + 4];
                contentBytes[0] = 0x81;
                contentBytes[1] = 126;
                contentBytes[2] = (byte)(temp.Length & 0xFF);
                contentBytes[3] = (byte)(temp.Length >> 8 & 0xFF);
                Array.Copy(temp, 0, contentBytes, 4, temp.Length);
            }
            else
            {
                // 暂不处理超长内容
            }

            return contentBytes;
        }

        /// <summary>
        /// 打包握手信息
        /// </summary>
        /// <param name="secKeyAccept">Sec-WebSocket-Accept</param>
        /// <returns>数据包</returns>
        public byte[] PackHandShakeData(string secKeyAccept)
        {
            var responseBuilder = new StringBuilder();
            responseBuilder.Append("HTTP/1.1 101 Switching Protocols" + Environment.NewLine);
            responseBuilder.Append("Upgrade: websocket" + Environment.NewLine);
            responseBuilder.Append("Connection: Upgrade" + Environment.NewLine);
            responseBuilder.Append("Sec-WebSocket-Accept: " + secKeyAccept + Environment.NewLine + Environment.NewLine);
            //如果把上一行换成下面两行，才是thewebsocketprotocol-17协议，但居然握手不成功，目前仍没弄明白！
            //responseBuilder.Append("Sec-WebSocket-Accept: " + secKeyAccept + Environment.NewLine);
            //responseBuilder.Append("Sec-WebSocket-Protocol: chat" + Environment.NewLine);

            return Encoding.UTF8.GetBytes(responseBuilder.ToString());
        }

        /// <summary>
        /// 生成Sec-WebSocket-Accept
        /// </summary>
        /// <param name="handShakeText">客户端握手信息</param>
        /// <returns>Sec-WebSocket-Accept</returns>
        public string GetSecKeyAccetp(byte[] handShakeBytes, int bytesLength)
        {
            string handShakeText = Encoding.UTF8.GetString(handShakeBytes, 0, bytesLength);
            string key = string.Empty;
            Regex r = new Regex(@"Sec\-WebSocket\-Key:(.*?)\r\n");
            Match m = r.Match(handShakeText);

            if (m.Groups.Count != 0)
            {
                key = Regex.Replace(m.Value, @"Sec\-WebSocket\-Key:(.*?)\r\n", "$1").Trim();
            }

            if (key == "")
            {
                return handShakeText;
            }

            byte[] encryptionString = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")); //这字符串是固定的.不能改
            string str = Convert.ToBase64String(encryptionString);

            return str;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="handShakeBytes"></param>
        /// <param name="bytesLength"></param>
        /// <returns></returns>
        public string GetSecKey(byte[] handShakeBytes, int bytesLength)
        {
            string handShakeText = Encoding.UTF8.GetString(handShakeBytes, 0, bytesLength);
            string key = string.Empty;
            Regex r = new Regex(@"Sec\-WebSocket\-Key:(.*?)\r\n");
            Match m = r.Match(handShakeText);

            if (m.Groups.Count != 0)
            {
                key = Regex.Replace(m.Value, @"Sec\-WebSocket\-Key:(.*?)\r\n", "$1").Trim();
            }

            if (key == "")
            {
                return string.Empty;
            }

            byte[] encryptionString = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")); //这字符串是固定的.不能改
            string str = Convert.ToBase64String(encryptionString);
            return str;
        }

        #endregion websocket模块

        #region 组件方法

        internal void CloseClient()
        {
            foreach (IClient iClient in ClientSocketList)
            {
                RemoveClient(iClient, "服务器主动关闭客户端");
            }
        }

        /// <summary>
        /// 关闭相连的scoket以及关联的TcpState,释放所有的资源
        /// </summary>
        /// <param name="iClient">TcpState</param>
        /// <param name="str">原因</param>
        internal void RemoveClient(IClient iClient, string str)
        {
            if (iClient == null)
            {
                return;
            }

            try
            {
                ShutdownClient(iClient);
                iClient.WorkSocket.Close();
                TcpServerOfflineClient(iClient);
                TcpServerGetLog(iClient, LogType.Client, str); //记录
            }
            catch (Exception ex)
            {
                TcpServerErrorMsg(string.Format("释放客户端资源时发生错误，错误原因：{0},行号{1}", ex.Message, ex.StackTrace));
            }
        }

        /// <summary>
        /// 强制断开与某个客户端的连接
        /// </summary>
        /// <param name="iClient"></param>
        public void ShutdownClient(IClient iClient)
        {
            try
            {
                iClient.WorkSocket.Shutdown(SocketShutdown.Both);
            }
            catch
            {
            }
        }

        #endregion 组件方法

        #region 发送数据

        /// <summary>
        /// 向指定客户端发送字符串数据
        /// </summary>
        /// <param name="iClient"></param>
        /// <param name="msg"></param>
        /// <param name="isHexString"></param>
        public void SendData(IClient iClient, string msg, bool isHexString = false)
        {
            byte[] data;
            if (isHexString)
            {
                data = ConvertStringManager.StringToHexByteArray(msg);
            }
            else
            {
                data = Encoding.Default.GetBytes(msg);
            }

            SendData(iClient, data);
        }

        /// <summary>
        /// 向指定IP和端口客户端发送字符串数据
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <param name="msg"></param>
        /// <param name="isHexString"></param>
        public void SendData(string ip, int port, string msg, bool isHexString = false)
        {
            IClient iClient = FindIClient(ip, port);
            if (iClient == null)
            {
                return;
            }

            byte[] data;
            if (isHexString)
            {
                data = ConvertStringManager.StringToHexByteArray(msg);
            }
            else
            {
                data = Encoding.Default.GetBytes(msg);
            }

            SendData(iClient, data);
        }

        /// <summary>
        /// 向指定IP和端口客户端发送数据
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <param name="data"></param>
        public void SendData(string ip, int port, byte[] data)
        {
            IClient iClient = FindIClient(ip, port);
            if (iClient == null)
            {
                return;
            }

            SendData(iClient, data);
        }

        /// <summary>
        /// 向指定客户端发送数据(基础)
        /// </summary>
        /// <param name="iClient">客户端</param>
        /// <param name="data">字节数组数据</param>
        public void SendData(IClient iClient, byte[] data)
        {
            try
            {
                if (iClient != null)
                {
                    if (!iClient.WorkSocket.Connected)
                    {
                        DisposeClient(iClient);
                        return;
                    }

                    //异步发送数据
                    //cModel.ClientSocket.Send(data);
                    iClient.WorkSocket.BeginSend(data, 0, data.Length, 0, new AsyncCallback(SendCallback), iClient);
                    iClient.BufferInfo.SendBuffer = data;
                    TcpServerGetLog(iClient, LogType.SendData, ConvertStringManager.HexByteArrayToString(data));
                }
            }
            catch (SocketException ex)
            {
                DisposeClient(iClient);
            }
        }

        public void DisposeClient(IClient iClient)
        {
            try
            {
                if (iClient == null)
                {
                    ClientSocketList.Remove(iClient);
                    TcpServerReturnClientCount(ClientSocketList.Count);
                    return;
                }

                ShutdownClient(iClient);
                TcpServerOfflineClient(iClient);
                TcpServerErrorMsg(string.Format("强制关闭远程客户端时发生错误"));
                TcpServerGetLog(iClient, LogType.SendData, "强制关闭远程客户端时发生错误");
                ClientSocketList.Remove(iClient);
                TcpServerReturnClientCount(ClientSocketList.Count);
            }
            catch
            {
            }
        }

        /// <summary>
        /// 发送完数据之后的回调函数
        /// </summary>
        /// <param name="ar">Clicent</param>
        private void SendCallback(IAsyncResult ar)
        {
            IClient iClient = (IClient)ar.AsyncState;
            try
            {
                if (iClient == null)
                {
                    return;
                }

                Socket handler = iClient.WorkSocket;

                int bytesSent = handler.EndSend(ar);
                TcpServerSendDateSuccess(iClient, bytesSent);
                TcpServerGetLog(iClient, LogType.SendDataResult, string.Format("发送成功，字节数：{0}", bytesSent));
            }
            catch (Exception ex)
            {
                TcpServerErrorMsg(string.Format("发送数据后回调时发生错误，错误原因：{0},行号{1}", ex.Message, ex.StackTrace));
                TcpServerGetLog(iClient, LogType.SendDataResult, string.Format("发送失败，失败原因：{0},行号{1}", ex.Message, ex.StackTrace));
            }
        }

        #endregion 发送数据

        #region 查找客户端方法

        /// <summary>
        /// 根据IP,端口查找Socket客户端
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public IClient FindIClient(string ip, int port)
        {
            try
            {
                foreach (IClient iClient in ClientSocketList)
                {
                    if (iClient.Ip.Equals(ip)
                        && iClient.Port.Equals(port))
                    {
                        return iClient;
                    }
                }
                return null;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        /// <summary>
        /// 根据IP,端口查找Socket客户端
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        public IClient FindIClient(string ip)
        {
            try
            {
                foreach (IClient iClient in ClientSocketList)
                {
                    if (iClient.Ip.Equals(ip))
                    {
                        return iClient;
                    }
                }
                return null;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        #endregion 查找客户端方法

        #region 注册事件

        #region OnRecevice接收数据事件

        /// <summary>
        /// 接收数据事件
        /// </summary>
        [Description("接收数据事件")]
        [Category("TcpServer事件")]
        public event EventHandler<TcpServerReceviceaEventArgs> OnRecevice;

        /// <summary>
        /// 接收数据事件
        /// </summary>
        /// <param name="iClient"></param>
        /// <param name="data"></param>
        protected virtual void TcpServerRecevice(IClient iClient, byte[] data)
        {
            if (OnRecevice != null)
            {
                CommonMethod.EventInvoket(() =>
                {
                    try
                    {
                        OnRecevice(this, new TcpServerReceviceaEventArgs(iClient, data));
                    }
                    catch (Exception ex)
                    {
                        TcpServerErrorMsg(string.Format("接收客户端数据时发生错误，错误原因：{0},行号{1}", ex.Message, ex.StackTrace));
                    }
                });
            }
        }

        #endregion OnRecevice接收数据事件

        #region OnErrorMsg返回错误消息事件

        /// <summary>
        /// 错误消息
        /// </summary>
        [Description("错误消息")]
        [Category("TcpServer事件")]
        public event EventHandler<TcpServerErrorEventArgs> OnErrorMsg;

        /// <summary>
        /// 错误消息
        /// </summary>
        /// <param name="msg"></param>
        protected virtual void TcpServerErrorMsg(string msg)
        {
            if (OnErrorMsg != null)
            {
                CommonMethod.EventInvoket(() => { OnErrorMsg(this, new TcpServerErrorEventArgs(msg)); });
            }
        }

        #endregion OnErrorMsg返回错误消息事件

        #region OnReturnClientCount用户上线下线时更新客户端在线数量事件

        /// <summary>
        /// 用户上线下线时更新客户端在线数量事件
        /// </summary>
        [Description("用户上线下线时更新客户端在线数量事件")]
        [Category("TcpServer事件")]
        public event EventHandler<TcpServerReturnClientCountEventArgs> OnReturnClientCount;

        /// <summary>
        /// 用户上线下线时更新客户端在线数量事件
        /// </summary>
        /// <param name="count"></param>
        protected virtual void TcpServerReturnClientCount(int count)
        {
            if (OnReturnClientCount != null)
            {
                CommonMethod.EventInvoket(() => { OnReturnClientCount(this, new TcpServerReturnClientCountEventArgs(count)); });
            }
        }

        #endregion OnReturnClientCount用户上线下线时更新客户端在线数量事件

        #region OnStateInfo监听状态改变时返回监听状态事件

        /// <summary>
        /// 监听状态改变时返回监听状态事件
        /// </summary>
        [Description("监听状态改变时返回监听状态事件")]
        [Category("TcpServer事件")]
        public event EventHandler<TcpServerStateEventArgs> OnStateInfo;

        /// <summary>
        /// 监听状态改变时返回监听状态事件
        /// </summary>
        /// <param name="iClient"></param>
        /// <param name="msg"></param>
        /// <param name="state"></param>
        protected virtual void TcpServerStateInfo(IClient iClient, string msg, SocketState state)
        {
            if (OnStateInfo != null)
            {
                CommonMethod.EventInvoket(() => { OnStateInfo(this, new TcpServerStateEventArgs(iClient, msg, state)); });
            }
        }

        #endregion OnStateInfo监听状态改变时返回监听状态事件

        #region OnAddClient新客户端上线时返回客户端事件

        /// <summary>
        /// 新客户端上线时返回客户端事件
        /// </summary>
        [Description("新客户端上线时返回客户端事件")]
        [Category("TcpServer事件")]
        public event EventHandler<TcpServerClientEventArgs> OnOnlineClient;

        /// <summary>
        /// 新客户端上线时返回客户端事件
        /// </summary>
        /// <param name="iclient"></param>
        protected virtual void TcpServerOnlineClient(IClient iclient)
        {
            if (OnOnlineClient != null)
            {
                CommonMethod.EventInvoket(() => { OnOnlineClient(this, new TcpServerClientEventArgs(iclient)); });
            }
        }

        #endregion OnAddClient新客户端上线时返回客户端事件

        #region OnOfflineClient客户端下线时返回客户端事件

        /// <summary>
        /// 客户端下线时返回客户端事件
        /// </summary>
        [Description("客户端下线时返回客户端事件")]
        [Category("TcpServer事件")]
        public event EventHandler<TcpServerClientEventArgs> OnOfflineClient;

        /// <summary>
        /// 客户端下线时返回客户端事件
        /// </summary>
        /// <param name="iclient"></param>
        protected virtual void TcpServerOfflineClient(IClient iclient)
        {
            if (OnOfflineClient != null)
            {
                ClientSocketList.Remove(iclient);
                CommonMethod.EventInvoket(() => { OnOfflineClient(this, new TcpServerClientEventArgs(iclient)); });
            }
        }

        #endregion OnOfflineClient客户端下线时返回客户端事件

        #region OnGetLog服务端读写操作时返回日志消息

        /// <summary>
        /// 服务端读写操作时返回日志消息
        /// </summary>
        [Description("服务端读写操作时返回日志消息")]
        [Category("TcpServer事件")]
        public event EventHandler<TcpServerLogEventArgs> OnGetLog;

        /// <summary>
        /// 服务端读写操作时返回日志消息
        /// </summary>
        /// <param name="temp"></param>
        /// <param name="logType"></param>
        /// <param name="logMsg"></param>
        protected virtual void TcpServerGetLog(IClient temp, LogType logType, string logMsg)
        {
            if (OnGetLog != null)
            {
                CommonMethod.EventInvoket(() => { OnGetLog(this, new TcpServerLogEventArgs(temp, logType, logMsg)); });
            }
        }

        #endregion OnGetLog服务端读写操作时返回日志消息

        #region OnSendDateSuccess发送消息成功时返回成功消息事件

        /// <summary>
        /// 发送消息成功时返回成功消息事件
        /// </summary>
        [Description("发送消息成功时返回成功消息事件")]
        [Category("TcpServer事件")]
        public event EventHandler<TcpServerSendReturnEventArgs> OnSendDateSuccess;

        /// <summary>
        /// 发送消息成功时返回成功消息事件
        /// </summary>
        /// <param name="temp"></param>
        /// <param name="byteLen"></param>
        protected virtual void TcpServerSendDateSuccess(IClient temp, int byteLen)
        {
            if (OnSendDateSuccess != null)
            {
                CommonMethod.EventInvoket(() => { OnSendDateSuccess(this, new TcpServerSendReturnEventArgs(temp, byteLen)); });
            }
        }

        #endregion OnSendDateSuccess发送消息成功时返回成功消息事件

        #endregion 注册事件
    }
}