栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C# 对 TCP 客户端的状态封装

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C# 对 TCP 客户端的状态封装

TCP客户端连接TCP服务器端有几种应用状态:

  1. 与服务器的连接已建立

  2. 与服务器的连接已断开

  3. 与服务器的连接发生异常

应用程序可按需求合理处理这些逻辑,比如:

  1. 连接断开后自动重连

  2. 连接断开后选择备用地址重连

  3. 所有状态变化上报告警

本文描述的TcpClient实现了状态变化的事件通知机制。

  1   ///   2   /// 异步TCP客户端  3   ///   4   public class AsyncTcpClient : IDisposable  5   {  6     #region Fields  7   8     private TcpClient tcpClient;  9     private bool disposed = false; 10     private int retries = 0; 11  12     #endregion 13  14     #region Ctors 15  16     ///  17     /// 异步TCP客户端 18     ///  19     /// 远端服务器终结点 20     public AsyncTcpClient(IPEndPoint remoteEP) 21       : this(new[] { remoteEP.Address }, remoteEP.Port) 22     { 23     } 24  25     ///  26     /// 异步TCP客户端 27     ///  28     /// 远端服务器终结点 29     /// 本地客户端终结点 30     public AsyncTcpClient(IPEndPoint remoteEP, IPEndPoint localEP) 31       : this(new[] { remoteEP.Address }, remoteEP.Port, localEP) 32     { 33     } 34  35     ///  36     /// 异步TCP客户端 37     ///  38     /// 远端服务器IP地址 39     /// 远端服务器端口 40     public AsyncTcpClient(IPAddress remoteIPAddress, int remotePort) 41       : this(new[] { remoteIPAddress }, remotePort) 42     { 43     } 44  45     ///  46     /// 异步TCP客户端 47     ///  48     /// 远端服务器IP地址 49     /// 远端服务器端口 50     /// 本地客户端终结点 51     public AsyncTcpClient( 52       IPAddress remoteIPAddress, int remotePort, IPEndPoint localEP) 53       : this(new[] { remoteIPAddress }, remotePort, localEP) 54     { 55     } 56  57     ///  58     /// 异步TCP客户端 59     ///  60     /// 远端服务器主机名 61     /// 远端服务器端口 62     public AsyncTcpClient(string remoteHostName, int remotePort) 63       : this(Dns.GetHostAddresses(remoteHostName), remotePort) 64     { 65     } 66  67     ///  68     /// 异步TCP客户端 69     ///  70     /// 远端服务器主机名 71     /// 远端服务器端口 72     /// 本地客户端终结点 73     public AsyncTcpClient( 74       string remoteHostName, int remotePort, IPEndPoint localEP) 75       : this(Dns.GetHostAddresses(remoteHostName), remotePort, localEP) 76     { 77     } 78  79     ///  80     /// 异步TCP客户端 81     ///  82     /// 远端服务器IP地址列表 83     /// 远端服务器端口 84     public AsyncTcpClient(IPAddress[] remoteIPAddresses, int remotePort) 85       : this(remoteIPAddresses, remotePort, null) 86     { 87     } 88  89     ///  90     /// 异步TCP客户端 91     ///  92     /// 远端服务器IP地址列表 93     /// 远端服务器端口 94     /// 本地客户端终结点 95     public AsyncTcpClient( 96       IPAddress[] remoteIPAddresses, int remotePort, IPEndPoint localEP) 97     { 98       this.Addresses = remoteIPAddresses; 99       this.Port = remotePort;100       this.LocalIPEndPoint = localEP;101       this.Encoding = Encoding.Default;102 103       if (this.LocalIPEndPoint != null)104       {105         this.tcpClient = new TcpClient(this.LocalIPEndPoint);106       }107       else108       {109         this.tcpClient = new TcpClient();110       }111 112       Retries = 3;113       RetryInterval = 5;114     }115 116     #endregion117 118     #region Properties119 120     /// 121     /// 是否已与服务器建立连接122     /// 123     public bool Connected { get { return tcpClient.Client.Connected; } }124     /// 125     /// 远端服务器的IP地址列表126     /// 127     public IPAddress[] Addresses { get; private set; }128     /// 129     /// 远端服务器的端口130     /// 131     public int Port { get; private set; }132     /// 133     /// 连接重试次数134     /// 135     public int Retries { get; set; }136     /// 137     /// 连接重试间隔138     /// 139     public int RetryInterval { get; set; }140     /// 141     /// 远端服务器终结点142     /// 143     public IPEndPoint RemoteIPEndPoint 
144     { 
145       get { return new IPEndPoint(Addresses[0], Port); } 
146     }147     /// 148     /// 本地客户端终结点149     /// 150     protected IPEndPoint LocalIPEndPoint { get; private set; }151     /// 152     /// 通信所使用的编码153     /// 154     public Encoding Encoding { get; set; }155 156     #endregion157 158     #region Connect159 160     /// 161     /// 连接到服务器162     /// 163     /// 异步TCP客户端164     public AsyncTcpClient Connect()165     {166       if (!Connected)167       {168         // start the async connect operation169         tcpClient.BeginConnect(170           Addresses, Port, HandleTcpServerConnected, tcpClient);171       }172 173       return this;174     }175 176     /// 177     /// 关闭与服务器的连接178     /// 179     /// 异步TCP客户端180     public AsyncTcpClient Close()181     {182       if (Connected)183       {184         retries = 0;185         tcpClient.Close();186         RaiseServerDisconnected(Addresses, Port);187       }188 189       return this;190     }191 192     #endregion193 194     #region Receive195 196     private void HandleTcpServerConnected(IAsyncResult ar)197     {198       try199       {200         tcpClient.EndConnect(ar);201         RaiseServerConnected(Addresses, Port);202         retries = 0;203       }204       catch (Exception ex)205       {206         ExceptionHandler.Handle(ex);207         if (retries > 0)208         {209           Logger.Debug(string.Format(CultureInfo.InvariantCulture, 
210             "Connect to server with retry {0} failed.", retries));211         }212 213         retries++;214         if (retries > Retries)215         {216           // we have failed to connect to all the IP Addresses, 
217           // connection has failed overall.218           RaiseServerExceptionOccurred(Addresses, Port, ex);219           return;220         }221         else222         {223           Logger.Debug(string.Format(CultureInfo.InvariantCulture, 
224             "Waiting {0} seconds before retrying to connect to server.", 
225             RetryInterval));226           Thread.Sleep(TimeSpan.FromSeconds(RetryInterval));227           Connect();228           return;229         }230       }231 232       // we are connected successfully and start asyn read operation.233       byte[] buffer = new byte[tcpClient.ReceiveBufferSize];234       tcpClient.GetStream().BeginRead(235         buffer, 0, buffer.Length, HandleDatagramReceived, buffer);236     }237 238     private void HandleDatagramReceived(IAsyncResult ar)239     {240       NetworkStream stream = tcpClient.GetStream();241 242       int numberOfReadBytes = 0;243       try244       {245         numberOfReadBytes = stream.EndRead(ar);246       }247       catch248       {249         numberOfReadBytes = 0;250       }251 252       if (numberOfReadBytes == 0)253       {254         // connection has been closed255         Close();256         return;257       }258 259       // received byte and trigger event notification260       byte[] buffer = (byte[])ar.AsyncState;261       byte[] receivedBytes = new byte[numberOfReadBytes];262       Buffer.BlockCopy(buffer, 0, receivedBytes, 0, numberOfReadBytes);263       RaiseDatagramReceived(tcpClient, receivedBytes);264       RaisePlaintextReceived(tcpClient, receivedBytes);265 266       // then start reading from the network again267       stream.BeginRead(268         buffer, 0, buffer.Length, HandleDatagramReceived, buffer);269     }270 271     #endregion272 273     #region Events274 275     /// 276     /// 接收到数据报文事件277     /// 278     public event EventHandler> DatagramReceived;279     /// 280     /// 接收到数据报文明文事件281     /// 282     public event EventHandler> PlaintextReceived;283 284     private void RaiseDatagramReceived(TcpClient sender, byte[] datagram)285     {286       if (DatagramReceived != null)287       {288         DatagramReceived(this, 
289           new TcpDatagramReceivedEventArgs(sender, datagram));290       }291     }292 293     private void RaisePlaintextReceived(TcpClient sender, byte[] datagram)294     {295       if (PlaintextReceived != null)296       {297         PlaintextReceived(this, 
298           new TcpDatagramReceivedEventArgs(299             sender, this.Encoding.GetString(datagram, 0, datagram.Length)));300       }301     }302 303     /// 304     /// 与服务器的连接已建立事件305     /// 306     public event EventHandler ServerConnected;307     /// 308     /// 与服务器的连接已断开事件309     /// 310     public event EventHandler ServerDisconnected;311     /// 312     /// 与服务器的连接发生异常事件313     /// 314     public event EventHandler ServerExceptionOccurred;315 316     private void RaiseServerConnected(IPAddress[] ipAddresses, int port)317     {318       if (ServerConnected != null)319       {320         ServerConnected(this, 
321           new TcpServerConnectedEventArgs(ipAddresses, port));322       }323     }324 325     private void RaiseServerDisconnected(IPAddress[] ipAddresses, int port)326     {327       if (ServerDisconnected != null)328       {329         ServerDisconnected(this, 
330           new TcpServerDisconnectedEventArgs(ipAddresses, port));331       }332     }333 334     private void RaiseServerExceptionOccurred(335       IPAddress[] ipAddresses, int port, Exception innerException)336     {337       if (ServerExceptionOccurred != null)338       {339         ServerExceptionOccurred(this, 
340           new TcpServerExceptionOccurredEventArgs(341             ipAddresses, port, innerException));342       }343     }344 345     #endregion346 347     #region Send348 349     /// 350     /// 发送报文351     /// 352     /// 报文353     public void Send(byte[] datagram)354     {355       if (datagram == null)356         throw new ArgumentNullException("datagram");357 358       if (!Connected)359       {360         RaiseServerDisconnected(Addresses, Port);361         throw new InvalidProgramException(362           "This client has not connected to server.");363       }364 365       tcpClient.GetStream().BeginWrite(366         datagram, 0, datagram.Length, HandleDatagramWritten, tcpClient);367     }368 369     private void HandleDatagramWritten(IAsyncResult ar)370     {371       ((TcpClient)ar.AsyncState).GetStream().EndWrite(ar);372     }373 374     /// 375     /// 发送报文376     /// 377     /// 报文378     public void Send(string datagram)379     {380       Send(this.Encoding.GetBytes(datagram));381     }382 383     #endregion384 385     #region IDisposable Members386 387     /// 388     /// Performs application-defined tasks associated with freeing, 
389     /// releasing, or resetting unmanaged resources.390     /// 391     public void Dispose()392     {393       Dispose(true);394       GC.SuppressFinalize(this);395     }396 397     /// 398     /// Releases unmanaged and - optionally - managed resources399     /// 400     /// true to release both managed 
401     /// and unmanaged resources; false 402     /// to release only unmanaged resources.403     /// 404     protected virtual void Dispose(bool disposing)405     {406       if (!this.disposed)407       {408         if (disposing)409         {410           try411           {412             Close();413 414             if (tcpClient != null)415             {416               tcpClient = null;417             }418           }419           catch (SocketException ex)420           {421             ExceptionHandler.Handle(ex);422           }423         }424 425         disposed = true;426       }427     }428 429     #endregion430   }


使用举例


 1   class Program 2   { 3     static AsyncTcpClient client; 4  5     static void Main(string[] args) 6     { 7       LogFactory.Assign(new ConsoleLogFactory()); 8  9       // 测试用,可以不指定由系统选择端口10       IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9999);11       IPEndPoint localEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9998); 
12       client = new AsyncTcpClient(remoteEP, localEP);13       client.Encoding = Encoding.UTF8;14       client.ServerExceptionOccurred += 
15         new EventHandler(client_ServerExceptionOccurred);16       client.ServerConnected += 
17         new EventHandler(client_ServerConnected);18       client.ServerDisconnected += 
19         new EventHandler(client_ServerDisconnected);20       client.PlaintextReceived += 
21         new EventHandler>(client_PlaintextReceived);22       client.Connect();23 24       Console.WriteLine("TCP client has connected to server.");25       Console.WriteLine("Type something to send to server...");26       while (true)27       {28         try29         {30           string text = Console.ReadLine();31           client.Send(text);32         }33         catch (Exception ex)34         {35           Console.WriteLine(ex.Message);36         }37       }38     }39 40     static void client_ServerExceptionOccurred(41       object sender, TcpServerExceptionOccurredEventArgs e)42     {43       Logger.Debug(string.Format(CultureInfo.InvariantCulture, 
44         "TCP server {0} exception occurred, {1}.", 
45         e.ToString(), e.Exception.Message));46     }47 48     static void client_ServerConnected(49       object sender, TcpServerConnectedEventArgs e)50     {51       Logger.Debug(string.Format(CultureInfo.InvariantCulture, 
52         "TCP server {0} has connected.", e.ToString()));53     }54 55     static void client_ServerDisconnected(56       object sender, TcpServerDisconnectedEventArgs e)57     {58       Logger.Debug(string.Format(CultureInfo.InvariantCulture, 
59         "TCP server {0} has disconnected.", e.ToString()));60     }61 62     static void client_PlaintextReceived(63       object sender, TcpDatagramReceivedEventArgs e)64     {65       Console.Write(string.Format("Server : {0} --> ", 
66         e.TcpClient.Client.RemoteEndPoint.ToString()));67       Console.WriteLine(string.Format("{0}", e.Datagram));68     }69   }


TCP客户端State


 1   ///  2   /// Internal class to join the TCP client and buffer together 3   /// for easy management in the server 4   ///  5   internal class TcpClientState 6   { 7     ///  8     /// Constructor for a new Client 9     /// 10     /// The TCP client11     /// The byte array buffer12     public TcpClientState(TcpClient tcpClient, byte[] buffer)13     {14       if (tcpClient == null)15         throw new ArgumentNullException("tcpClient");16       if (buffer == null)17         throw new ArgumentNullException("buffer");18 19       this.TcpClient = tcpClient;20       this.Buffer = buffer;21     }22 23     /// 24     /// Gets the TCP Client25     /// 26     public TcpClient TcpClient { get; private set; }27 28     /// 29     /// Gets the Buffer.30     /// 31     public byte[] Buffer { get; private set; }32 33     /// 34     /// Gets the network stream35     /// 36     public NetworkStream NetworkStream37     {38       get { return TcpClient.GetStream(); }39     }40   }


与客户端的连接已建立事件参数


 1   ///  2   /// 与客户端的连接已建立事件参数 3   ///  4   public class TcpClientConnectedEventArgs : EventArgs 5   { 6     ///  7     /// 与客户端的连接已建立事件参数 8     ///  9     /// 客户端10     public TcpClientConnectedEventArgs(TcpClient tcpClient)11     {12       if (tcpClient == null)13         throw new ArgumentNullException("tcpClient");14 15       this.TcpClient = tcpClient;16     }17 18     /// 19     /// 客户端20     /// 21     public TcpClient TcpClient { get; private set; }22   }


与客户端的连接已断开事件参数


  /// 
  /// 与客户端的连接已断开事件参数  /// 
  public class TcpClientDisconnectedEventArgs : EventArgs
  {    /// 
    /// 与客户端的连接已断开事件参数    /// 
    /// 客户端
    public TcpClientDisconnectedEventArgs(TcpClient tcpClient)
    {      if (tcpClient == null)        throw new ArgumentNullException("tcpClient");      this.TcpClient = tcpClient;
    }    /// 
    /// 客户端    /// 
    public TcpClient TcpClient { get; private set; }
  }


与服务器的连接发生异常事件参数


 1   ///  2   /// 与服务器的连接发生异常事件参数 3   ///  4   public class TcpServerExceptionOccurredEventArgs : EventArgs 5   { 6     ///  7     /// 与服务器的连接发生异常事件参数 8     ///  9     /// 服务器IP地址列表10     /// 服务器端口11     /// 内部异常12     public TcpServerExceptionOccurredEventArgs(13       IPAddress[] ipAddresses, int port, Exception innerException)14     {15       if (ipAddresses == null)16         throw new ArgumentNullException("ipAddresses");17 18       this.Addresses = ipAddresses;19       this.Port = port;20       this.Exception = innerException;21     }22 23     /// 24     /// 服务器IP地址列表25     /// 26     public IPAddress[] Addresses { get; private set; }27     /// 28     /// 服务器端口29     /// 30     public int Port { get; private set; }31     /// 32     /// 内部异常33     /// 34     public Exception Exception { get; private set; }35 36     /// 37     /// Returns a  that represents this instance.38     /// 39     /// 40     /// A  that represents this instance.41     /// 42     public override string ToString()43     {44       string s = string.Empty;45       foreach (var item in Addresses)46       {47         s = s + item.ToString() + ',';48       }49       s = s.TrimEnd(',');50       s = s + ":" + Port.ToString(CultureInfo.InvariantCulture);51 52       return s;53     }54   }


接收到数据报文事件参数


 1   ///  2   /// 接收到数据报文事件参数 3   ///  4   /// 报文类型 5   public class TcpDatagramReceivedEventArgs : EventArgs 6   { 7     ///  8     /// 接收到数据报文事件参数 9     /// 10     /// 客户端11     /// 报文12     public TcpDatagramReceivedEventArgs(TcpClient tcpClient, T datagram)13     {14       TcpClient = tcpClient;15       Datagram = datagram;16     }17 18     /// 19     /// 客户端20     /// 21     public TcpClient TcpClient { get; private set; }22     /// 23     /// 报文24     /// 25     public T Datagram { get; private set; }26   }


与服务器的连接已建立事件参数


 1   ///  2   /// 与服务器的连接已建立事件参数 3   ///  4   public class TcpServerConnectedEventArgs : EventArgs 5   { 6     ///  7     /// 与服务器的连接已建立事件参数 8     ///  9     /// 服务器IP地址列表10     /// 服务器端口11     public TcpServerConnectedEventArgs(IPAddress[] ipAddresses, int port)12     {13       if (ipAddresses == null)14         throw new ArgumentNullException("ipAddresses");15 16       this.Addresses = ipAddresses;17       this.Port = port;18     }19 20     /// 21     /// 服务器IP地址列表22     /// 23     public IPAddress[] Addresses { get; private set; }24     /// 25     /// 服务器端口26     /// 27     public int Port { get; private set; }28 29     /// 30     /// Returns a  that represents this instance.31     /// 32     /// 33     /// A  that represents this instance.34     /// 35     public override string ToString()36     {37       string s = string.Empty;38       foreach (var item in Addresses)39       {40         s = s + item.ToString() + ',';41       }42       s = s.TrimEnd(',');43       s = s + ":" + Port.ToString(CultureInfo.InvariantCulture);44 45       return s;46     }47   }


与服务器的连接已断开事件参数


 1   ///  2   /// 与服务器的连接已断开事件参数 3   ///  4   public class TcpServerDisconnectedEventArgs : EventArgs 5   { 6     ///  7     /// 与服务器的连接已断开事件参数 8     ///  9     /// 服务器IP地址列表10     /// 服务器端口11     public TcpServerDisconnectedEventArgs(IPAddress[] ipAddresses, int port)12     {13       if (ipAddresses == null)14         throw new ArgumentNullException("ipAddresses");15 16       this.Addresses = ipAddresses;17       this.Port = port;18     }19 20     /// 21     /// 服务器IP地址列表22     /// 23     public IPAddress[] Addresses { get; private set; }24     /// 25     /// 服务器端口26     /// 27     public int Port { get; private set; }28 29     /// 30     /// Returns a  that represents this instance.31     /// 32     /// 33     /// A  that represents this instance.34     /// 35     public override string ToString()36     {37       string s = string.Empty;38       foreach (var item in Addresses)39       {40         s = s + item.ToString() + ',';41       }42       s = s.TrimEnd(',');43       s = s + ":" + Port.ToString(CultureInfo.InvariantCulture);44 45       return s;46     }47   }


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/231445.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号