少年修仙传客户端基础资源
lwb
2020-11-11 ba24a4a15c0317ac2fd954f4173b4b79cbdf191e
Assets/Plugins/PocoSDK/TcpServer.cs
@@ -10,16 +10,16 @@
namespace TcpServer
{
   public interface ProtoFilter
   {
      void input(byte[] data);
    public interface ProtoFilter
    {
        void input(byte[] data);
      List<string> swap_msgs();
   }
        List<string> swap_msgs();
    }
   public class SimpleProtocolFilter : ProtoFilter
   {
      /* 简单协议过滤器
    public class SimpleProtocolFilter : ProtoFilter
    {
        /* 简单协议过滤器
      协议按照 [有效数据字节数][有效数据] 这种协议包的格式进行打包和解包
      [有效数据字节数]长度HEADER_SIZE字节
      [有效数据]长度有效数据字节数字节
@@ -28,580 +28,580 @@
      所有编解码的操作在该类中完成
      */
      private byte[] buf = new byte[0];
      private int HEADER_SIZE = 4;
      private List<string> msgs = new List<string>();
        private byte[] buf = new byte[0];
        private int HEADER_SIZE = 4;
        private List<string> msgs = new List<string>();
      public void input(byte[] data)
      {
         buf = Combine(buf, data);
        public void input(byte[] data)
        {
            buf = Combine(buf, data);
         while (buf.Length > HEADER_SIZE)
         {
            int data_size = BitConverter.ToInt32(buf, 0);
            if (buf.Length >= data_size + HEADER_SIZE)
            {
               byte[] data_body = Slice(buf, HEADER_SIZE, data_size + HEADER_SIZE);
               string content = System.Text.Encoding.Default.GetString(data_body);
               msgs.Add(content);
               buf = Slice(buf, data_size + HEADER_SIZE, buf.Length);
            }
            else
            {
               break;
            }
         }
      }
            while (buf.Length > HEADER_SIZE)
            {
                int data_size = BitConverter.ToInt32(buf, 0);
                if (buf.Length >= data_size + HEADER_SIZE)
                {
                    byte[] data_body = Slice(buf, HEADER_SIZE, data_size + HEADER_SIZE);
                    string content = System.Text.Encoding.Default.GetString(data_body);
                    msgs.Add(content);
                    buf = Slice(buf, data_size + HEADER_SIZE, buf.Length);
                }
                else
                {
                    break;
                }
            }
        }
      public List<string> swap_msgs()
      {
         List<string> ret = msgs;
         msgs = new List<string>();
         return ret;
      }
        public List<string> swap_msgs()
        {
            List<string> ret = msgs;
            msgs = new List<string>();
            return ret;
        }
      public byte[] pack(String content)
      {
         int len = content.Length;
         byte[] size = BitConverter.GetBytes(len);
         if (!BitConverter.IsLittleEndian)
         {
            //reverse it so we get little endian.
            Array.Reverse(size);
         }
         byte[] body = System.Text.Encoding.Default.GetBytes(content);
         byte[] ret = Combine(size, body);
         return ret;
      }
        public byte[] pack(String content)
        {
            int len = content.Length;
            byte[] size = BitConverter.GetBytes(len);
            if (!BitConverter.IsLittleEndian)
            {
                //reverse it so we get little endian.
                Array.Reverse(size);
            }
            byte[] body = System.Text.Encoding.Default.GetBytes(content);
            byte[] ret = Combine(size, body);
            return ret;
        }
      private static byte[] Combine(byte[] first, byte[] second)
      {
         byte[] ret = new byte[first.Length + second.Length];
         Buffer.BlockCopy(first, 0, ret, 0, first.Length);
         Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);
         return ret;
      }
        private static byte[] Combine(byte[] first, byte[] second)
        {
            byte[] ret = new byte[first.Length + second.Length];
            Buffer.BlockCopy(first, 0, ret, 0, first.Length);
            Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);
            return ret;
        }
      public byte[] Slice(byte[] source, int start, int end)
      {
         int length = end - start;
         byte[] ret = new byte[length];
         Array.Copy(source, start, ret, 0, length);
         return ret;
      }
   }
        public byte[] Slice(byte[] source, int start, int end)
        {
            int length = end - start;
            byte[] ret = new byte[length];
            Array.Copy(source, start, ret, 0, length);
            return ret;
        }
    }
   /// <summary>
   /// 异步TCP服务器
   /// </summary>
   public class AsyncTcpServer : IDisposable
   {
      #region Fields
    /// <summary>
    /// 异步TCP服务器
    /// </summary>
    public class AsyncTcpServer : IDisposable
    {
        #region Fields
      private TcpListener _listener;
      private ConcurrentDictionary<string, TcpClientState> _clients;
      private bool _disposed = false;
        private TcpListener _listener;
        private ConcurrentDictionary<string, TcpClientState> _clients;
        private bool _disposed = false;
      #endregion
        #endregion
      #region Ctors
        #region Ctors
      /// <summary>
      /// 异步TCP服务器
      /// </summary>
      /// <param name="listenPort">监听的端口</param>
      public AsyncTcpServer(int listenPort)
         : this(IPAddress.Any, listenPort)
      {
      }
        /// <summary>
        /// 异步TCP服务器
        /// </summary>
        /// <param name="listenPort">监听的端口</param>
        public AsyncTcpServer(int listenPort)
            : this(IPAddress.Any, listenPort)
        {
        }
      /// <summary>
      /// 异步TCP服务器
      /// </summary>
      /// <param name="localEP">监听的终结点</param>
      public AsyncTcpServer(IPEndPoint localEP)
         : this(localEP.Address, localEP.Port)
      {
      }
        /// <summary>
        /// 异步TCP服务器
        /// </summary>
        /// <param name="localEP">监听的终结点</param>
        public AsyncTcpServer(IPEndPoint localEP)
            : this(localEP.Address, localEP.Port)
        {
        }
      /// <summary>
      /// 异步TCP服务器
      /// </summary>
      /// <param name="localIPAddress">监听的IP地址</param>
      /// <param name="listenPort">监听的端口</param>
      public AsyncTcpServer(IPAddress localIPAddress, int listenPort)
      {
         this.Address = localIPAddress;
         this.Port = listenPort;
         this.Encoding = Encoding.Default;
        /// <summary>
        /// 异步TCP服务器
        /// </summary>
        /// <param name="localIPAddress">监听的IP地址</param>
        /// <param name="listenPort">监听的端口</param>
        public AsyncTcpServer(IPAddress localIPAddress, int listenPort)
        {
            this.Address = localIPAddress;
            this.Port = listenPort;
            this.Encoding = Encoding.Default;
         _clients = new ConcurrentDictionary<string, TcpClientState>();
            _clients = new ConcurrentDictionary<string, TcpClientState>();
         _listener = new TcpListener(Address, Port);
         // _listener.AllowNatTraversal(true);
      }
            _listener = new TcpListener(Address, Port);
            // _listener.AllowNatTraversal(true);
        }
      #endregion
        #endregion
      #region Properties
        #region Properties
      /// <summary>
      /// 服务器是否正在运行
      /// </summary>
      public bool IsRunning { get; private set; }
        /// <summary>
        /// 服务器是否正在运行
        /// </summary>
        public bool IsRunning { get; private set; }
      /// <summary>
      /// 监听的IP地址
      /// </summary>
      public IPAddress Address { get; private set; }
        /// <summary>
        /// 监听的IP地址
        /// </summary>
        public IPAddress Address { get; private set; }
      /// <summary>
      /// 监听的端口
      /// </summary>
      public int Port { get; private set; }
        /// <summary>
        /// 监听的端口
        /// </summary>
        public int Port { get; private set; }
      /// <summary>
      /// 通信使用的编码
      /// </summary>
      public Encoding Encoding { get; set; }
        /// <summary>
        /// 通信使用的编码
        /// </summary>
        public Encoding Encoding { get; set; }
      #endregion
        #endregion
      #region Server
        #region Server
      /// <summary>
      /// 启动服务器
      /// </summary>
      /// <returns>异步TCP服务器</returns>
      public AsyncTcpServer Start()
      {
         Debug.Log("start server");
         return Start(10);
      }
        /// <summary>
        /// 启动服务器
        /// </summary>
        /// <returns>异步TCP服务器</returns>
        public AsyncTcpServer Start()
        {
            Debug.Log("start server");
            return Start(10);
        }
      /// <summary>
      /// 启动服务器
      /// </summary>
      /// <param name="backlog">服务器所允许的挂起连接序列的最大长度</param>
      /// <returns>异步TCP服务器</returns>
      public AsyncTcpServer Start(int backlog)
      {
         if (IsRunning)
            return this;
        /// <summary>
        /// 启动服务器
        /// </summary>
        /// <param name="backlog">服务器所允许的挂起连接序列的最大长度</param>
        /// <returns>异步TCP服务器</returns>
        public AsyncTcpServer Start(int backlog)
        {
            if (IsRunning)
                return this;
         IsRunning = true;
            IsRunning = true;
         _listener.Start(backlog);
         ContinueAcceptTcpClient(_listener);
            _listener.Start(backlog);
            ContinueAcceptTcpClient(_listener);
         return this;
      }
            return this;
        }
      /// <summary>
      /// 停止服务器
      /// </summary>
      /// <returns>异步TCP服务器</returns>
      public AsyncTcpServer Stop()
      {
         if (!IsRunning)
            return this;
        /// <summary>
        /// 停止服务器
        /// </summary>
        /// <returns>异步TCP服务器</returns>
        public AsyncTcpServer Stop()
        {
            if (!IsRunning)
                return this;
         try
         {
            _listener.Stop();
            try
            {
                _listener.Stop();
            foreach (var client in _clients.Values)
            {
               client.TcpClient.Client.Disconnect(false);
            }
            _clients.Clear();
         }
         catch (ObjectDisposedException ex)
         {
            Debug.LogException(ex);
         }
         catch (SocketException ex)
         {
            Debug.LogException(ex);
         }
                foreach (var client in _clients.Values)
                {
                    client.TcpClient.Client.Disconnect(false);
                }
                _clients.Clear();
            }
            catch (ObjectDisposedException ex)
            {
                Debug.LogException(ex);
            }
            catch (SocketException ex)
            {
                Debug.LogException(ex);
            }
         IsRunning = false;
            IsRunning = false;
         return this;
      }
            return this;
        }
      private void ContinueAcceptTcpClient(TcpListener tcpListener)
      {
         try
         {
            tcpListener.BeginAcceptTcpClient(new AsyncCallback(HandleTcpClientAccepted), tcpListener);
         }
         catch (ObjectDisposedException ex)
         {
            Debug.LogException(ex);
         }
         catch (SocketException ex)
         {
            Debug.LogException(ex);
         }
      }
        private void ContinueAcceptTcpClient(TcpListener tcpListener)
        {
            try
            {
                tcpListener.BeginAcceptTcpClient(new AsyncCallback(HandleTcpClientAccepted), tcpListener);
            }
            catch (ObjectDisposedException ex)
            {
                Debug.LogException(ex);
            }
            catch (SocketException ex)
            {
                Debug.LogException(ex);
            }
        }
      #endregion
        #endregion
      #region Receive
        #region Receive
      private void HandleTcpClientAccepted(IAsyncResult ar)
      {
         if (!IsRunning)
            return;
        private void HandleTcpClientAccepted(IAsyncResult ar)
        {
            if (!IsRunning)
                return;
         TcpListener tcpListener = (TcpListener)ar.AsyncState;
            TcpListener tcpListener = (TcpListener)ar.AsyncState;
         TcpClient tcpClient = tcpListener.EndAcceptTcpClient(ar);
         if (!tcpClient.Connected)
            return;
            TcpClient tcpClient = tcpListener.EndAcceptTcpClient(ar);
            if (!tcpClient.Connected)
                return;
         byte[] buffer = new byte[tcpClient.ReceiveBufferSize];
         SimpleProtocolFilter prot = new SimpleProtocolFilter();
         TcpClientState internalClient = new TcpClientState(tcpClient, buffer, prot);
            byte[] buffer = new byte[tcpClient.ReceiveBufferSize];
            SimpleProtocolFilter prot = new SimpleProtocolFilter();
            TcpClientState internalClient = new TcpClientState(tcpClient, buffer, prot);
         // add client connection to cache
         string tcpClientKey = internalClient.TcpClient.Client.RemoteEndPoint.ToString();
         _clients.AddOrUpdate(tcpClientKey, internalClient, (n, o) =>
         {
            return internalClient;
         });
         RaiseClientConnected(tcpClient);
            // add client connection to cache
            string tcpClientKey = internalClient.TcpClient.Client.RemoteEndPoint.ToString();
            _clients.AddOrUpdate(tcpClientKey, internalClient, (n, o) =>
            {
                return internalClient;
            });
            RaiseClientConnected(tcpClient);
         // begin to read data
         NetworkStream networkStream = internalClient.NetworkStream;
         ContinueReadBuffer(internalClient, networkStream);
            // begin to read data
            NetworkStream networkStream = internalClient.NetworkStream;
            ContinueReadBuffer(internalClient, networkStream);
         // keep listening to accept next connection
         ContinueAcceptTcpClient(tcpListener);
      }
            // keep listening to accept next connection
            ContinueAcceptTcpClient(tcpListener);
        }
      private void HandleDatagramReceived(IAsyncResult ar)
      {
         if (!IsRunning)
            return;
        private void HandleDatagramReceived(IAsyncResult ar)
        {
            if (!IsRunning)
                return;
         try
         {
            TcpClientState internalClient = (TcpClientState)ar.AsyncState;
            if (!internalClient.TcpClient.Connected)
               return;
            try
            {
                TcpClientState internalClient = (TcpClientState)ar.AsyncState;
                if (!internalClient.TcpClient.Connected)
                    return;
            NetworkStream networkStream = internalClient.NetworkStream;
                NetworkStream networkStream = internalClient.NetworkStream;
            int numberOfReadBytes = 0;
            try
            {
               // if the remote host has shutdown its connection,
               // read will immediately return with zero bytes.
               numberOfReadBytes = networkStream.EndRead(ar);
            }
            catch (Exception ex)
            {
               Debug.LogException(ex);
               numberOfReadBytes = 0;
            }
                int numberOfReadBytes = 0;
                try
                {
                    // if the remote host has shutdown its connection,
                    // read will immediately return with zero bytes.
                    numberOfReadBytes = networkStream.EndRead(ar);
                }
                catch (Exception ex)
                {
                    Debug.LogException(ex);
                    numberOfReadBytes = 0;
                }
            if (numberOfReadBytes == 0)
            {
               // connection has been closed
               TcpClientState internalClientToBeThrowAway;
               string tcpClientKey = internalClient.TcpClient.Client.RemoteEndPoint.ToString();
               _clients.TryRemove(tcpClientKey, out internalClientToBeThrowAway);
               RaiseClientDisconnected(internalClient.TcpClient);
               return;
            }
                if (numberOfReadBytes == 0)
                {
                    // connection has been closed
                    TcpClientState internalClientToBeThrowAway;
                    string tcpClientKey = internalClient.TcpClient.Client.RemoteEndPoint.ToString();
                    _clients.TryRemove(tcpClientKey, out internalClientToBeThrowAway);
                    RaiseClientDisconnected(internalClient.TcpClient);
                    return;
                }
            // received byte and trigger event notification
            var receivedBytes = new byte[numberOfReadBytes];
            Array.Copy(internalClient.Buffer, 0, receivedBytes, 0, numberOfReadBytes);
            // input bytes into protofilter
            internalClient.Prot.input(receivedBytes);
            RaiseDatagramReceived(internalClient, receivedBytes);
            // RaisePlaintextReceived(internalClient.TcpClient, receivedBytes);
                // received byte and trigger event notification
                var receivedBytes = new byte[numberOfReadBytes];
                Array.Copy(internalClient.Buffer, 0, receivedBytes, 0, numberOfReadBytes);
                // input bytes into protofilter
                internalClient.Prot.input(receivedBytes);
                RaiseDatagramReceived(internalClient, receivedBytes);
                // RaisePlaintextReceived(internalClient.TcpClient, receivedBytes);
            // continue listening for tcp datagram packets
            ContinueReadBuffer(internalClient, networkStream);
         }
         catch (InvalidOperationException ex)
         {
            Debug.LogException(ex);
         }
      }
                // continue listening for tcp datagram packets
                ContinueReadBuffer(internalClient, networkStream);
            }
            catch (InvalidOperationException ex)
            {
                Debug.LogException(ex);
            }
        }
      private void ContinueReadBuffer(TcpClientState internalClient, NetworkStream networkStream)
      {
         try
         {
            networkStream.BeginRead(internalClient.Buffer, 0, internalClient.Buffer.Length, HandleDatagramReceived, internalClient);
         }
         catch (ObjectDisposedException ex)
         {
            Debug.LogException(ex);
         }
      }
        private void ContinueReadBuffer(TcpClientState internalClient, NetworkStream networkStream)
        {
            try
            {
                networkStream.BeginRead(internalClient.Buffer, 0, internalClient.Buffer.Length, HandleDatagramReceived, internalClient);
            }
            catch (ObjectDisposedException ex)
            {
                Debug.LogException(ex);
            }
        }
      #endregion
        #endregion
      #region Events
        #region Events
      /// <summary>
      /// 接收到数据报文事件
      /// </summary>
      public event EventHandler<TcpDatagramReceivedEventArgs<byte[]>> DatagramReceived;
      /// <summary>
      /// 接收到数据报文明文事件
      /// </summary>
      public event EventHandler<TcpDatagramReceivedEventArgs<string>> PlaintextReceived;
        /// <summary>
        /// 接收到数据报文事件
        /// </summary>
        public event EventHandler<TcpDatagramReceivedEventArgs<byte[]>> DatagramReceived;
        /// <summary>
        /// 接收到数据报文明文事件
        /// </summary>
        public event EventHandler<TcpDatagramReceivedEventArgs<string>> PlaintextReceived;
      private void RaiseDatagramReceived(TcpClientState sender, byte[] datagram)
      {
         if (DatagramReceived != null)
         {
            DatagramReceived(this, new TcpDatagramReceivedEventArgs<byte[]>(sender, datagram));
         }
      }
        private void RaiseDatagramReceived(TcpClientState sender, byte[] datagram)
        {
            if (DatagramReceived != null)
            {
                DatagramReceived(this, new TcpDatagramReceivedEventArgs<byte[]>(sender, datagram));
            }
        }
      private void RaisePlaintextReceived(TcpClientState sender, byte[] datagram)
      {
         if (PlaintextReceived != null)
         {
            PlaintextReceived(this, new TcpDatagramReceivedEventArgs<string>(sender, this.Encoding.GetString(datagram, 0, datagram.Length)));
         }
      }
        private void RaisePlaintextReceived(TcpClientState sender, byte[] datagram)
        {
            if (PlaintextReceived != null)
            {
                PlaintextReceived(this, new TcpDatagramReceivedEventArgs<string>(sender, this.Encoding.GetString(datagram, 0, datagram.Length)));
            }
        }
      /// <summary>
      /// 与客户端的连接已建立事件
      /// </summary>
      public event EventHandler<TcpClientConnectedEventArgs> ClientConnected;
      /// <summary>
      /// 与客户端的连接已断开事件
      /// </summary>
      public event EventHandler<TcpClientDisconnectedEventArgs> ClientDisconnected;
        /// <summary>
        /// 与客户端的连接已建立事件
        /// </summary>
        public event EventHandler<TcpClientConnectedEventArgs> ClientConnected;
        /// <summary>
        /// 与客户端的连接已断开事件
        /// </summary>
        public event EventHandler<TcpClientDisconnectedEventArgs> ClientDisconnected;
      private void RaiseClientConnected(TcpClient tcpClient)
      {
         if (ClientConnected != null)
         {
            ClientConnected(this, new TcpClientConnectedEventArgs(tcpClient));
         }
      }
        private void RaiseClientConnected(TcpClient tcpClient)
        {
            if (ClientConnected != null)
            {
                ClientConnected(this, new TcpClientConnectedEventArgs(tcpClient));
            }
        }
      private void RaiseClientDisconnected(TcpClient tcpClient)
      {
         if (ClientDisconnected != null)
         {
            ClientDisconnected(this, new TcpClientDisconnectedEventArgs(tcpClient));
         }
      }
        private void RaiseClientDisconnected(TcpClient tcpClient)
        {
            if (ClientDisconnected != null)
            {
                ClientDisconnected(this, new TcpClientDisconnectedEventArgs(tcpClient));
            }
        }
      #endregion
        #endregion
      #region Send
        #region Send
      private void GuardRunning()
      {
         if (!IsRunning)
            throw new InvalidProgramException("This TCP server has not been started yet.");
      }
        private void GuardRunning()
        {
            if (!IsRunning)
                throw new InvalidProgramException("This TCP server has not been started yet.");
        }
      /// <summary>
      /// 发送报文至指定的客户端
      /// </summary>
      /// <param name="tcpClient">客户端</param>
      /// <param name="datagram">报文</param>
      public void Send(TcpClient tcpClient, byte[] datagram)
      {
         GuardRunning();
        /// <summary>
        /// 发送报文至指定的客户端
        /// </summary>
        /// <param name="tcpClient">客户端</param>
        /// <param name="datagram">报文</param>
        public void Send(TcpClient tcpClient, byte[] datagram)
        {
            GuardRunning();
         if (tcpClient == null)
            throw new ArgumentNullException("tcpClient");
            if (tcpClient == null)
                throw new ArgumentNullException("tcpClient");
         if (datagram == null)
            throw new ArgumentNullException("datagram");
            if (datagram == null)
                throw new ArgumentNullException("datagram");
         try
         {
            NetworkStream stream = tcpClient.GetStream();
            if (stream.CanWrite)
            {
               stream.BeginWrite(datagram, 0, datagram.Length, HandleDatagramWritten, tcpClient);
            }
         }
         catch (ObjectDisposedException ex)
         {
            Debug.LogException(ex);
         }
      }
            try
            {
                NetworkStream stream = tcpClient.GetStream();
                if (stream.CanWrite)
                {
                    stream.BeginWrite(datagram, 0, datagram.Length, HandleDatagramWritten, tcpClient);
                }
            }
            catch (ObjectDisposedException ex)
            {
                Debug.LogException(ex);
            }
        }
      /// <summary>
      /// 发送报文至指定的客户端
      /// </summary>
      /// <param name="tcpClient">客户端</param>
      /// <param name="datagram">报文</param>
      public void Send(TcpClient tcpClient, string datagram)
      {
         Send(tcpClient, this.Encoding.GetBytes(datagram));
      }
        /// <summary>
        /// 发送报文至指定的客户端
        /// </summary>
        /// <param name="tcpClient">客户端</param>
        /// <param name="datagram">报文</param>
        public void Send(TcpClient tcpClient, string datagram)
        {
            Send(tcpClient, this.Encoding.GetBytes(datagram));
        }
      /// <summary>
      /// 发送报文至所有客户端
      /// </summary>
      /// <param name="datagram">报文</param>
      public void SendToAll(byte[] datagram)
      {
         GuardRunning();
        /// <summary>
        /// 发送报文至所有客户端
        /// </summary>
        /// <param name="datagram">报文</param>
        public void SendToAll(byte[] datagram)
        {
            GuardRunning();
         foreach (var client in _clients.Values)
         {
            Send(client.TcpClient, datagram);
         }
      }
            foreach (var client in _clients.Values)
            {
                Send(client.TcpClient, datagram);
            }
        }
      /// <summary>
      /// 发送报文至所有客户端
      /// </summary>
      /// <param name="datagram">报文</param>
      public void SendToAll(string datagram)
      {
         GuardRunning();
        /// <summary>
        /// 发送报文至所有客户端
        /// </summary>
        /// <param name="datagram">报文</param>
        public void SendToAll(string datagram)
        {
            GuardRunning();
         SendToAll(this.Encoding.GetBytes(datagram));
      }
            SendToAll(this.Encoding.GetBytes(datagram));
        }
      private void HandleDatagramWritten(IAsyncResult ar)
      {
         try
         {
            ((TcpClient)ar.AsyncState).GetStream().EndWrite(ar);
         }
         catch (ObjectDisposedException ex)
         {
            Debug.LogException(ex);
         }
         catch (InvalidOperationException ex)
         {
            Debug.LogException(ex);
         }
         catch (IOException ex)
         {
            Debug.LogException(ex);
         }
      }
        private void HandleDatagramWritten(IAsyncResult ar)
        {
            try
            {
                ((TcpClient)ar.AsyncState).GetStream().EndWrite(ar);
            }
            catch (ObjectDisposedException ex)
            {
                Debug.LogException(ex);
            }
            catch (InvalidOperationException ex)
            {
                Debug.LogException(ex);
            }
            catch (IOException ex)
            {
                Debug.LogException(ex);
            }
        }
      /// <summary>
      /// 发送报文至指定的客户端
      /// </summary>
      /// <param name="tcpClient">客户端</param>
      /// <param name="datagram">报文</param>
      public void SyncSend(TcpClient tcpClient, byte[] datagram)
      {
         GuardRunning();
        /// <summary>
        /// 发送报文至指定的客户端
        /// </summary>
        /// <param name="tcpClient">客户端</param>
        /// <param name="datagram">报文</param>
        public void SyncSend(TcpClient tcpClient, byte[] datagram)
        {
            GuardRunning();
         if (tcpClient == null)
            throw new ArgumentNullException("tcpClient");
            if (tcpClient == null)
                throw new ArgumentNullException("tcpClient");
         if (datagram == null)
            throw new ArgumentNullException("datagram");
            if (datagram == null)
                throw new ArgumentNullException("datagram");
         try
         {
            NetworkStream stream = tcpClient.GetStream();
            if (stream.CanWrite)
            {
               stream.Write(datagram, 0, datagram.Length);
            }
         }
         catch (ObjectDisposedException ex)
         {
            Debug.LogException(ex);
         }
      }
            try
            {
                NetworkStream stream = tcpClient.GetStream();
                if (stream.CanWrite)
                {
                    stream.Write(datagram, 0, datagram.Length);
                }
            }
            catch (ObjectDisposedException ex)
            {
                Debug.LogException(ex);
            }
        }
      /// <summary>
      /// 发送报文至指定的客户端
      /// </summary>
      /// <param name="tcpClient">客户端</param>
      /// <param name="datagram">报文</param>
      public void SyncSend(TcpClient tcpClient, string datagram)
      {
         SyncSend(tcpClient, this.Encoding.GetBytes(datagram));
      }
        /// <summary>
        /// 发送报文至指定的客户端
        /// </summary>
        /// <param name="tcpClient">客户端</param>
        /// <param name="datagram">报文</param>
        public void SyncSend(TcpClient tcpClient, string datagram)
        {
            SyncSend(tcpClient, this.Encoding.GetBytes(datagram));
        }
      /// <summary>
      /// 发送报文至所有客户端
      /// </summary>
      /// <param name="datagram">报文</param>
      public void SyncSendToAll(byte[] datagram)
      {
         GuardRunning();
        /// <summary>
        /// 发送报文至所有客户端
        /// </summary>
        /// <param name="datagram">报文</param>
        public void SyncSendToAll(byte[] datagram)
        {
            GuardRunning();
         foreach (var client in _clients.Values)
         {
            SyncSend(client.TcpClient, datagram);
         }
      }
            foreach (var client in _clients.Values)
            {
                SyncSend(client.TcpClient, datagram);
            }
        }
      /// <summary>
      /// 发送报文至所有客户端
      /// </summary>
      /// <param name="datagram">报文</param>
      public void SyncSendToAll(string datagram)
      {
         GuardRunning();
        /// <summary>
        /// 发送报文至所有客户端
        /// </summary>
        /// <param name="datagram">报文</param>
        public void SyncSendToAll(string datagram)
        {
            GuardRunning();
         SyncSendToAll(this.Encoding.GetBytes(datagram));
      }
            SyncSendToAll(this.Encoding.GetBytes(datagram));
        }
      #endregion
        #endregion
      #region IDisposable Members
        #region IDisposable Members
      /// <summary>
      /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
      /// </summary>
      public void Dispose()
      {
         Dispose(true);
         GC.SuppressFinalize(this);
      }
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
      /// <summary>
      /// Releases unmanaged and - optionally - managed resources
      /// </summary>
      /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources;
      /// <c>false</c> to release only unmanaged resources.</param>
      protected virtual void Dispose(bool disposing)
      {
         if (!this._disposed)
         {
            if (disposing)
            {
               try
               {
                  Stop();
        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources;
        /// <c>false</c> to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!this._disposed)
            {
                if (disposing)
                {
                    try
                    {
                        Stop();
                  if (_listener != null)
                  {
                     _listener = null;
                  }
               }
               catch (SocketException ex)
               {
                  Debug.LogException(ex);
               }
            }
                        if (_listener != null)
                        {
                            _listener = null;
                        }
                    }
                    catch (SocketException ex)
                    {
                        Debug.LogException(ex);
                    }
                }
            _disposed = true;
         }
      }
                _disposed = true;
            }
        }
      #endregion
   }
        #endregion
    }
}