C# 对 TCP 客户端的状态封装
TCP客户端连接TCP服务器端有几种应用状态:
- 与服务器的连接已建立
- 与服务器的连接已断开
- 与服务器的连接发生异常
应用程序可按需求合理处理这些逻辑,比如:
- 连接断开后自动重连
- 连接断开后选择备用地址重连
- 所有状态变化上报告警
本文描述的TcpClient实现了状态变化的事件通知机制。

- 1 /// <summary>
- 2 /// 异步TCP客户端
- 3 /// </summary>
- 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 /// <summary>
- 17 /// 异步TCP客户端
- 18 /// </summary>
- 19 /// <param name="remoteEP">远端服务器终结点</param>
- 20 public AsyncTcpClient(IPEndPoint remoteEP)
- 21 : this(new[] { remoteEP.Address }, remoteEP.Port)
- 22 {
- 23 }
- 24
- 25 /// <summary>
- 26 /// 异步TCP客户端
- 27 /// </summary>
- 28 /// <param name="remoteEP">远端服务器终结点</param>
- 29 /// <param name="localEP">本地客户端终结点</param>
- 30 public AsyncTcpClient(IPEndPoint remoteEP, IPEndPoint localEP)
- 31 : this(new[] { remoteEP.Address }, remoteEP.Port, localEP)
- 32 {
- 33 }
- 34
- 35 /// <summary>
- 36 /// 异步TCP客户端
- 37 /// </summary>
- 38 /// <param name="remoteIPAddress">远端服务器IP地址</param>
- 39 /// <param name="remotePort">远端服务器端口</param>
- 40 public AsyncTcpClient(IPAddress remoteIPAddress, int remotePort)
- 41 : this(new[] { remoteIPAddress }, remotePort)
- 42 {
- 43 }
- 44
- 45 /// <summary>
- 46 /// 异步TCP客户端
- 47 /// </summary>
- 48 /// <param name="remoteIPAddress">远端服务器IP地址</param>
- 49 /// <param name="remotePort">远端服务器端口</param>
- 50 /// <param name="localEP">本地客户端终结点</param>
- 51 public AsyncTcpClient(
- 52 IPAddress remoteIPAddress, int remotePort, IPEndPoint localEP)
- 53 : this(new[] { remoteIPAddress }, remotePort, localEP)
- 54 {
- 55 }
- 56
- 57 /// <summary>
- 58 /// 异步TCP客户端
- 59 /// </summary>
- 60 /// <param name="remoteHostName">远端服务器主机名</param>
- 61 /// <param name="remotePort">远端服务器端口</param>
- 62 public AsyncTcpClient(string remoteHostName, int remotePort)
- 63 : this(Dns.GetHostAddresses(remoteHostName), remotePort)
- 64 {
- 65 }
- 66
- 67 /// <summary>
- 68 /// 异步TCP客户端
- 69 /// </summary>
- 70 /// <param name="remoteHostName">远端服务器主机名</param>
- 71 /// <param name="remotePort">远端服务器端口</param>
- 72 /// <param name="localEP">本地客户端终结点</param>
- 73 public AsyncTcpClient(
- 74 string remoteHostName, int remotePort, IPEndPoint localEP)
- 75 : this(Dns.GetHostAddresses(remoteHostName), remotePort, localEP)
- 76 {
- 77 }
- 78
- 79 /// <summary>
- 80 /// 异步TCP客户端
- 81 /// </summary>
- 82 /// <param name="remoteIPAddresses">远端服务器IP地址列表</param>
- 83 /// <param name="remotePort">远端服务器端口</param>
- 84 public AsyncTcpClient(IPAddress[] remoteIPAddresses, int remotePort)
- 85 : this(remoteIPAddresses, remotePort, null)
- 86 {
- 87 }
- 88
- 89 /// <summary>
- 90 /// 异步TCP客户端
- 91 /// </summary>
- 92 /// <param name="remoteIPAddresses">远端服务器IP地址列表</param>
- 93 /// <param name="remotePort">远端服务器端口</param>
- 94 /// <param name="localEP">本地客户端终结点</param>
- 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 else
- 108 {
- 109 this.tcpClient = new TcpClient();
- 110 }
- 111
- 112 Retries = 3;
- 113 RetryInterval = 5;
- 114 }
- 115
- 116 #endregion
- 117
- 118 #region Properties
- 119
- 120 /// <summary>
- 121 /// 是否已与服务器建立连接
- 122 /// </summary>
- 123 public bool Connected { get { return tcpClient.Client.Connected; } }
- 124 /// <summary>
- 125 /// 远端服务器的IP地址列表
- 126 /// </summary>
- 127 public IPAddress[] Addresses { get; private set; }
- 128 /// <summary>
- 129 /// 远端服务器的端口
- 130 /// </summary>
- 131 public int Port { get; private set; }
- 132 /// <summary>
- 133 /// 连接重试次数
- 134 /// </summary>
- 135 public int Retries { get; set; }
- 136 /// <summary>
- 137 /// 连接重试间隔
- 138 /// </summary>
- 139 public int RetryInterval { get; set; }
- 140 /// <summary>
- 141 /// 远端服务器终结点
- 142 /// </summary>
- 143 public IPEndPoint RemoteIPEndPoint
- 144 {
- 145 get { return new IPEndPoint(Addresses[0], Port); }
- 146 }
- 147 /// <summary>
- 148 /// 本地客户端终结点
- 149 /// </summary>
- 150 protected IPEndPoint LocalIPEndPoint { get; private set; }
- 151 /// <summary>
- 152 /// 通信所使用的编码
- 153 /// </summary>
- 154 public Encoding Encoding { get; set; }
- 155
- 156 #endregion
- 157
- 158 #region Connect
- 159
- 160 /// <summary>
- 161 /// 连接到服务器
- 162 /// </summary>
- 163 /// <returns>异步TCP客户端</returns>
- 164 public AsyncTcpClient Connect()
- 165 {
- 166 if (!Connected)
- 167 {
- 168 // start the async connect operation
- 169 tcpClient.BeginConnect(
- 170 Addresses, Port, HandleTcpServerConnected, tcpClient);
- 171 }
- 172
- 173 return this;
- 174 }
- 175
- 176 /// <summary>
- 177 /// 关闭与服务器的连接
- 178 /// </summary>
- 179 /// <returns>异步TCP客户端</returns>
- 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 #endregion
- 193
- 194 #region Receive
- 195
- 196 private void HandleTcpServerConnected(IAsyncResult ar)
- 197 {
- 198 try
- 199 {
- 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 else
- 222 {
- 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 try
- 244 {
- 245 numberOfReadBytes = stream.EndRead(ar);
- 246 }
- 247 catch
- 248 {
- 249 numberOfReadBytes = 0;
- 250 }
- 251
- 252 if (numberOfReadBytes == 0)
- 253 {
- 254 // connection has been closed
- 255 Close();
- 256 return;
- 257 }
- 258
- 259 // received byte and trigger event notification
- 260 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 again
- 267 stream.BeginRead(
- 268 buffer, 0, buffer.Length, HandleDatagramReceived, buffer);
- 269 }
- 270
- 271 #endregion
- 272
- 273 #region Events
- 274
- 275 /// <summary>
- 276 /// 接收到数据报文事件
- 277 /// </summary>
- 278 public event EventHandler<TcpDatagramReceivedEventArgs<byte[]>> DatagramReceived;
- 279 /// <summary>
- 280 /// 接收到数据报文明文事件
- 281 /// </summary>
- 282 public event EventHandler<TcpDatagramReceivedEventArgs<string>> PlaintextReceived;
- 283
- 284 private void RaiseDatagramReceived(TcpClient sender, byte[] datagram)
- 285 {
- 286 if (DatagramReceived != null)
- 287 {
- 288 DatagramReceived(this,
- 289 new TcpDatagramReceivedEventArgs<byte[]>(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<string>(
- 299 sender, this.Encoding.GetString(datagram, 0, datagram.Length)));
- 300 }
- 301 }
- 302
- 303 /// <summary>
- 304 /// 与服务器的连接已建立事件
- 305 /// </summary>
- 306 public event EventHandler<TcpServerConnectedEventArgs> ServerConnected;
- 307 /// <summary>
- 308 /// 与服务器的连接已断开事件
- 309 /// </summary>
- 310 public event EventHandler<TcpServerDisconnectedEventArgs> ServerDisconnected;
- 311 /// <summary>
- 312 /// 与服务器的连接发生异常事件
- 313 /// </summary>
- 314 public event EventHandler<TcpServerExceptionOccurredEventArgs> 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 #endregion
- 346
- 347 #region Send
- 348
- 349 /// <summary>
- 350 /// 发送报文
- 351 /// </summary>
- 352 /// <param name="datagram">报文</param>
- 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 /// <summary>
- 375 /// 发送报文
- 376 /// </summary>
- 377 /// <param name="datagram">报文</param>
- 378 public void Send(string datagram)
- 379 {
- 380 Send(this.Encoding.GetBytes(datagram));
- 381 }
- 382
- 383 #endregion
- 384
- 385 #region IDisposable Members
- 386
- 387 /// <summary>
- 388 /// Performs application-defined tasks associated with freeing,
- 389 /// releasing, or resetting unmanaged resources.
- 390 /// </summary>
- 391 public void Dispose()
- 392 {
- 393 Dispose(true);
- 394 GC.SuppressFinalize(this);
- 395 }
- 396
- 397 /// <summary>
- 398 /// Releases unmanaged and - optionally - managed resources
- 399 /// </summary>
- 400 /// <param name="disposing"><c>true</c> to release both managed
- 401 /// and unmanaged resources; <c>false</c>
- 402 /// to release only unmanaged resources.
- 403 /// </param>
- 404 protected virtual void Dispose(bool disposing)
- 405 {
- 406 if (!this.disposed)
- 407 {
- 408 if (disposing)
- 409 {
- 410 try
- 411 {
- 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 #endregion
- 430 }

使用举例

- 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<TcpServerExceptionOccurredEventArgs>(client_ServerExceptionOccurred);
- 16 client.ServerConnected +=
- 17 new EventHandler<TcpServerConnectedEventArgs>(client_ServerConnected);
- 18 client.ServerDisconnected +=
- 19 new EventHandler<TcpServerDisconnectedEventArgs>(client_ServerDisconnected);
- 20 client.PlaintextReceived +=
- 21 new EventHandler<TcpDatagramReceivedEventArgs<string>>(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 try
- 29 {
- 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<string> 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 /// <summary>
- 2 /// Internal class to join the TCP client and buffer together
- 3 /// for easy management in the server
- 4 /// </summary>
- 5 internal class TcpClientState
- 6 {
- 7 /// <summary>
- 8 /// Constructor for a new Client
- 9 /// </summary>
- 10 /// <param name="tcpClient">The TCP client</param>
- 11 /// <param name="buffer">The byte array buffer</param>
- 12 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 /// <summary>
- 24 /// Gets the TCP Client
- 25 /// </summary>
- 26 public TcpClient TcpClient { get; private set; }
- 27
- 28 /// <summary>
- 29 /// Gets the Buffer.
- 30 /// </summary>
- 31 public byte[] Buffer { get; private set; }
- 32
- 33 /// <summary>
- 34 /// Gets the network stream
- 35 /// </summary>
- 36 public NetworkStream NetworkStream
- 37 {
- 38 get { return TcpClient.GetStream(); }
- 39 }
- 40 }

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

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

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

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

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

- 1 /// <summary>
- 2 /// 与服务器的连接发生异常事件参数
- 3 /// </summary>
- 4 public class TcpServerExceptionOccurredEventArgs : EventArgs
- 5 {
- 6 /// <summary>
- 7 /// 与服务器的连接发生异常事件参数
- 8 /// </summary>
- 9 /// <param name="ipAddresses">服务器IP地址列表</param>
- 10 /// <param name="port">服务器端口</param>
- 11 /// <param name="innerException">内部异常</param>
- 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 /// <summary>
- 24 /// 服务器IP地址列表
- 25 /// </summary>
- 26 public IPAddress[] Addresses { get; private set; }
- 27 /// <summary>
- 28 /// 服务器端口
- 29 /// </summary>
- 30 public int Port { get; private set; }
- 31 /// <summary>
- 32 /// 内部异常
- 33 /// </summary>
- 34 public Exception Exception { get; private set; }
- 35
- 36 /// <summary>
- 37 /// Returns a <see cref="System.String"/> that represents this instance.
- 38 /// </summary>
- 39 /// <returns>
- 40 /// A <see cref="System.String"/> that represents this instance.
- 41 /// </returns>
- 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 /// <summary>
- 2 /// 接收到数据报文事件参数
- 3 /// </summary>
- 4 /// <typeparam name="T">报文类型</typeparam>
- 5 public class TcpDatagramReceivedEventArgs<T> : EventArgs
- 6 {
- 7 /// <summary>
- 8 /// 接收到数据报文事件参数
- 9 /// </summary>
- 10 /// <param name="tcpClient">客户端</param>
- 11 /// <param name="datagram">报文</param>
- 12 public TcpDatagramReceivedEventArgs(TcpClient tcpClient, T datagram)
- 13 {
- 14 TcpClient = tcpClient;
- 15 Datagram = datagram;
- 16 }
- 17
- 18 /// <summary>
- 19 /// 客户端
- 20 /// </summary>
- 21 public TcpClient TcpClient { get; private set; }
- 22 /// <summary>
- 23 /// 报文
- 24 /// </summary>
- 25 public T Datagram { get; private set; }
- 26 }

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

- 1 /// <summary>
- 2 /// 与服务器的连接已建立事件参数
- 3 /// </summary>
- 4 public class TcpServerConnectedEventArgs : EventArgs
- 5 {
- 6 /// <summary>
- 7 /// 与服务器的连接已建立事件参数
- 8 /// </summary>
- 9 /// <param name="ipAddresses">服务器IP地址列表</param>
- 10 /// <param name="port">服务器端口</param>
- 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 /// <summary>
- 21 /// 服务器IP地址列表
- 22 /// </summary>
- 23 public IPAddress[] Addresses { get; private set; }
- 24 /// <summary>
- 25 /// 服务器端口
- 26 /// </summary>
- 27 public int Port { get; private set; }
- 28
- 29 /// <summary>
- 30 /// Returns a <see cref="System.String"/> that represents this instance.
- 31 /// </summary>
- 32 /// <returns>
- 33 /// A <see cref="System.String"/> that represents this instance.
- 34 /// </returns>
- 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 /// <summary>
- 2 /// 与服务器的连接已断开事件参数
- 3 /// </summary>
- 4 public class TcpServerDisconnectedEventArgs : EventArgs
- 5 {
- 6 /// <summary>
- 7 /// 与服务器的连接已断开事件参数
- 8 /// </summary>
- 9 /// <param name="ipAddresses">服务器IP地址列表</param>
- 10 /// <param name="port">服务器端口</param>
- 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 /// <summary>
- 21 /// 服务器IP地址列表
- 22 /// </summary>
- 23 public IPAddress[] Addresses { get; private set; }
- 24 /// <summary>
- 25 /// 服务器端口
- 26 /// </summary>
- 27 public int Port { get; private set; }
- 28
- 29 /// <summary>
- 30 /// Returns a <see cref="System.String"/> that represents this instance.
- 31 /// </summary>
- 32 /// <returns>
- 33 /// A <see cref="System.String"/> that represents this instance.
- 34 /// </returns>
- 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 }

C# 对 TCP 客户端的状态封装的更多相关文章
- 在C#中对TCP客户端的状态封装详解
引用地址: https://www.jb51.net/article/35689.htm
- 系统编程-网络-tcp客户端服务器编程模型(续)、连接断开、获取连接状态场景
相关博文: 系统编程-网络-tcp客户端服务器编程模型.socket.htons.inet_ntop等各API详解.使用telnet测试基本服务器功能 接着该上篇博文,咱们继续,首先,为了内容的完整性 ...
- tcp客户端封装
1.头文件 #ifndef TCPCLIENT_H #define TCPCLIENT_H #include <QTcpSocket> class TcpClient : public Q ...
- 29-ESP8266 SDK开发基础入门篇--编写TCP 客户端程序(Lwip RAW模式,非RTOS版,精简入门)
https://www.cnblogs.com/yangfengwu/p/11456667.html 由于上一节的源码长时间以后会自动断开,所以再做这一版非RTOS版的,咱直接用lua源码里面别人写的 ...
- TCP/IP连接状态
1.建立连接协议(三次握手)(1)客户端发送一个带SYN标志的TCP报文到服务器.这是三次握手过程中的报文1.(2) 服务器端回应客户端的,这是三次握手中的第2个报文,这个报文同时带ACK标志和SYN ...
- TCP连接的状态与关闭方式及其对Server与Client的影响
TCP连接的状态与关闭方式及其对Server与Client的影响 1. TCP连接的状态 首先介绍一下TCP连接建立与关闭过程中的状态.TCP连接过程是状态的转换,促使状态发生转换的因素包括用户调用. ...
- TCP连接的状态详解以及故障排查
我们通过了解 TCP各个状态 ,可以排除和定位网络或系统故障时大有帮助. 一.TCP状态 LISTENING :侦听来自远方的TCP端口的连接请求 . 首先服务端需要打开一个 socket 进行监听, ...
- 【RL-TCPnet网络教程】第14章 RL-TCPnet之TCP客户端
第14章 RL-TCPnet之TCP客户端 本章节为大家讲解RL-TCPnet的TCP客户端实现,学习本章节前,务必要优先学习第12章TCP传输控制协议基础知识.有了这些基础知识之后,再搞本 ...
- TCP连接的状态与关闭方式,及其对Server与Client的影响
1. TCP连接的状态 首先介绍一下TCP连接建立与关闭过程中的状态.TCP连接过程是状态的转换,促使状态发生转换的因素包括用户调用.特定数据包以及超时等,具体状态如下所示: CLOSED:初始状态, ...
随机推荐
- Shell:Day03笔记
编程原理:1.编程结束 驱动 硬件默认是不能使用的 CPU控制硬件 不同的厂家硬件设备之间需要进行指令沟通,就需要驱动程序来进行“翻译” 编程语言的分类: 高级语言.超高级语言需要翻 ...
- 【mysql】mysql优化
一,表设计 1.1. E-R(entity relation)实体关系图 长方形 实体 表 椭圆形 属性 字段 菱形 关系 一对一 多对一 属于 多对多 1.2. 三范式标准 原子性 个人信息 省市县 ...
- java文件中字母出现的次数和百分比
主要是文件的读写.先在代码中导入文件.一行一行的进行数据的读入,通过“ ”空格对读入的信息进行分割,存入到数组里之后对于每一个单词的每一个字母进行区分存入相应的字母数组里.最后统计总的字母个数.应用 ...
- postman 工具接口测试
一.get:请求多个参数时,需要用&连接 eg:http://api.***.cn/api/user/stu_info?stu_name=小黑&set=女 eg:接口请求参数放在b ...
- Powershell如何制定属性并输出
这个标题看着有些云里雾里.... 前一阵,群里有个朋友问博主“我想把所有用户的SMTP地址全部输出到CSV文件中进行统计,但是SMTP地址似乎输出的是错误的,可在shell里看输出的内容是正确的阿” ...
- @suppressWarnings("unchecked") java 中是什么意思 (一般放dao查询方法上)
J2SE 提供的最后一个批注是 @SuppressWarnings.该批注的作用是给编译器一条指令,告诉它对被批注的代码元素内部的某些警告保持静默. 一点背景:J2SE 5.0 为 Java 语言增加 ...
- 关于《Python自动化测试实战》
作者有话说 笔者写这本书的初心是想通过自身经验分享一些在自动化测试领域中的实用技术,能够帮助那些正在从事自动化测试相关工作或者准备转型自动化测试的测试人员.任何一门技术涵盖的知识点都是非常广泛的,可能 ...
- android学习笔记——计时器实现
根据android疯狂讲义来写写代码,在博客里面将这些写过的代码汇总一下.实现的功能很简单:就是一个简单的计时器,点击启动按钮会开始计时,当计时到20秒时会自动停止计时. 界面如下: 界面代码: &l ...
- 学习Salesforce | Einstein业务机会评分怎么玩
Einstein 业务机会评分(Opportunity Scoring)是销售团队的得力助手,通过分数以及研究影响分数的因素,确定业务机会的优先级,赢得更多交易. Einstein 业务机会评分可以给 ...
- Python-元组tuple、列表list、字典dict
1.元组tuple(1)元组是有序列表,有不可见的下标,下标从0开始(2)元组的数据是相对固定的,数据不能增删改,他的一个重要用途是保存固定的.安全要求高的数据(3)元组用小括号()括起来,空元组定义 ...