C#对TCP客户端的状态封装 TCP客户端连接TCP服务器端有几种应用状态:
与服务器的连接已建立 与服务器的连接已断开 与服务器的连接发生异常 应用程序可按需求合理处理这些逻辑,比如:
连接断开后自动重连 连接断开后选择备用地址重连 所有状态变化上报告警 本文描述的TcpClient实现了状态变化的事件通知机制。
复制代码 1/// 2///异步TCP客户端 3/// 4publicclassAsyncTcpClient:IDisposable 5{ 6#regionFields 7 8privateTcpClienttcpClient; 9privatebooldisposed=false; 10privateintretries=0; 11 12#endregion 13 14#regionCtors 15 16/// 17///异步TCP客户端 18/// 19///远端服务器终结点 20publicAsyncTcpClient(IPEndPointremoteEP) 21:this(new[]{remoteEP.Address},remoteEP.Port) 22{ 23} 24 25/// 26///异步TCP客户端 27/// 28///远端服务器终结点 29///本地客户端终结点 30publicAsyncTcpClient(IPEndPointremoteEP,IPEndPointlocalEP) 31:this(new[]{remoteEP.Address},remoteEP.Port,localEP) 32{ 33} 34 35/// 36///异步TCP客户端 37/// 38///远端服务器IP地址 39///远端服务器端口 40publicAsyncTcpClient(IPAddressremoteIPAddress,intremotePort) 41:this(new[]{remoteIPAddress},remotePort) 42{ 43} 44 45/// 46///异步TCP客户端 47/// 48///远端服务器IP地址 49///远端服务器端口 50///本地客户端终结点 51publicAsyncTcpClient( 52IPAddressremoteIPAddress,intremotePort,IPEndPointlocalEP) 53:this(new[]{remoteIPAddress},remotePort,localEP) 54{ 55} 56 57/// 58///异步TCP客户端 59/// 60///远端服务器主机名 61///远端服务器端口 62publicAsyncTcpClient(stringremoteHostName,intremotePort) 63:this(Dns.GetHostAddresses(remoteHostName),remotePort) 64{ 65} 66 67/// 68///异步TCP客户端 69/// 70///远端服务器主机名 71///远端服务器端口 72///本地客户端终结点 73publicAsyncTcpClient( 74stringremoteHostName,intremotePort,IPEndPointlocalEP) 75:this(Dns.GetHostAddresses(remoteHostName),remotePort,localEP) 76{ 77} 78 79/// 80///异步TCP客户端 81/// 82///远端服务器IP地址列表 83///远端服务器端口 84publicAsyncTcpClient(IPAddress[]remoteIPAddresses,intremotePort) 85:this(remoteIPAddresses,remotePort,null) 86{ 87} 88 89/// 90///异步TCP客户端 91/// 92///远端服务器IP地址列表 93///远端服务器端口 94///本地客户端终结点 95publicAsyncTcpClient( 96IPAddress[]remoteIPAddresses,intremotePort,IPEndPointlocalEP) 97{ 98this.Addresses=remoteIPAddresses; 99this.Port=remotePort; 100this.LocalIPEndPoint=localEP; 101this.Encoding=Encoding.Default; 102 103if(this.LocalIPEndPoint!=null) 104{ 105this.tcpClient=newTcpClient(this.LocalIPEndPoint); 106} 107else 108{ 109this.tcpClient=newTcpClient(); 110} 111 112Retries=3; 113RetryInterval=5; 114} 115 116#endregion 117 118#regionProperties 119 120/// 121///是否已与服务器建立连接 122/// 123publicboolConnected{get{returntcpClient.Client.Connected;}} 124/// 125///远端服务器的IP地址列表 126/// 127publicIPAddress[]Addresses{get;privateset;} 128/// 129///远端服务器的端口 130/// 131publicintPort{get;privateset;} 132/// 133///连接重试次数 134/// 135publicintRetries{get;set;} 136/// 137///连接重试间隔 138/// 139publicintRetryInterval{get;set;} 140/// 141///远端服务器终结点 142/// 143publicIPEndPointRemoteIPEndPoint 144{ 145get{returnnewIPEndPoint(Addresses[0],Port);} 146} 147/// 148///本地客户端终结点 149/// 150protectedIPEndPointLocalIPEndPoint{get;privateset;} 151/// 152///通信所使用的编码 153/// 154publicEncodingEncoding{get;set;} 155 156#endregion 157 158#regionConnect 159 160/// 161///连接到服务器 162/// 163///异步TCP客户端 164publicAsyncTcpClientConnect() 165{ 166if(!Connected) 167{ 168//starttheasyncconnectoperation 169tcpClient.BeginConnect( 170Addresses,Port,HandleTcpServerConnected,tcpClient); 171} 172 173returnthis; 174} 175 176/// 177///关闭与服务器的连接 178/// 179///异步TCP客户端 180publicAsyncTcpClientClose() 181{ 182if(Connected) 183{ 184retries=0; 185tcpClient.Close(); 186RaiseServerDisconnected(Addresses,Port); 187} 188 189returnthis; 190} 191 192#endregion 193 194#regionReceive 195 196privatevoidHandleTcpServerConnected(IAsyncResultar) 197{ 198try 199{ 200tcpClient.EndConnect(ar); 201RaiseServerConnected(Addresses,Port); 202retries=0; 203} 204catch(Exceptionex) 205{ 206ExceptionHandler.Handle(ex); 207if(retries>0) 208{ 209Logger.Debug(string.Format(CultureInfo.InvariantCulture, 210"Connecttoserverwithretry{0}failed.",retries)); 211} 212 213retries++; 214if(retries>Retries) 215{ 216//wehavefailedtoconnecttoalltheIPAddresses, 217//connectionhasfailedoverall. 218RaiseServerExceptionOccurred(Addresses,Port,ex); 219return; 220} 221else 222{ 223Logger.Debug(string.Format(CultureInfo.InvariantCulture, 224"Waiting{0}secondsbeforeretryingtoconnecttoserver.", 225RetryInterval)); 226Thread.Sleep(TimeSpan.FromSeconds(RetryInterval)); 227Connect(); 228return; 229} 230} 231 232//weareconnectedsuccessfullyandstartasynreadoperation. 233byte[]buffer=newbyte[tcpClient.ReceiveBufferSize]; 234tcpClient.GetStream().BeginRead( 235buffer,0,buffer.Length,HandleDatagramReceived,buffer); 236} 237 238privatevoidHandleDatagramReceived(IAsyncResultar) 239{ 240NetworkStreamstream=tcpClient.GetStream(); 241 242intnumberOfReadBytes=0; 243try 244{ 245numberOfReadBytes=stream.EndRead(ar); 246} 247catch 248{ 249numberOfReadBytes=0; 250} 251 252if(numberOfReadBytes==0) 253{ 254//connectionhasbeenclosed 255Close(); 256return; 257} 258 259//receivedbyteandtriggereventnotification 260byte[]buffer=(byte[])ar.AsyncState; 261byte[]receivedBytes=newbyte[numberOfReadBytes]; 262Buffer.BlockCopy(buffer,0,receivedBytes,0,numberOfReadBytes); 263RaiseDatagramReceived(tcpClient,receivedBytes); 264RaisePlaintextReceived(tcpClient,receivedBytes); 265 266//thenstartreadingfromthenetworkagain 267stream.BeginRead( 268buffer,0,buffer.Length,HandleDatagramReceived,buffer); 269} 270 271#endregion 272 273#regionEvents 274 275/// 276///接收到数据报文事件 277/// 278publiceventEventHandler>DatagramReceived; 279/// 280///接收到数据报文明文事件 281/// 282publiceventEventHandler>PlaintextReceived; 283 284privatevoidRaiseDatagramReceived(TcpClientsender,byte[]datagram) 285{ 286if(DatagramReceived!=null) 287{ 288DatagramReceived(this, 289newTcpDatagramReceivedEventArgs(sender,datagram)); 290} 291} 292 293privatevoidRaisePlaintextReceived(TcpClientsender,byte[]datagram) 294{ 295if(PlaintextReceived!=null) 296{ 297PlaintextReceived(this, 298newTcpDatagramReceivedEventArgs( 299sender,this.Encoding.GetString(datagram,0,datagram.Length))); 300} 301} 302 303/// 304///与服务器的连接已建立事件 305/// 306publiceventEventHandlerServerConnected; 307/// 308///与服务器的连接已断开事件 309/// 310publiceventEventHandlerServerDisconnected; 311/// 312///与服务器的连接发生异常事件 313/// 314publiceventEventHandlerServerExceptionOccurred; 315 316privatevoidRaiseServerConnected(IPAddress[]ipAddresses,intport) 317{ 318if(ServerConnected!=null) 319{ 320ServerConnected(this, 321newTcpServerConnectedEventArgs(ipAddresses,port)); 322} 323} 324 325privatevoidRaiseServerDisconnected(IPAddress[]ipAddresses,intport) 326{ 327if(ServerDisconnected!=null) 328{ 329ServerDisconnected(this, 330newTcpServerDisconnectedEventArgs(ipAddresses,port)); 331} 332} 333 334privatevoidRaiseServerExceptionOccurred( 335IPAddress[]ipAddresses,intport,ExceptioninnerException) 336{ 337if(ServerExceptionOccurred!=null) 338{ 339ServerExceptionOccurred(this, 340newTcpServerExceptionOccurredEventArgs( 341ipAddresses,port,innerException)); 342} 343} 344 345#endregion 346 347#regionSend 348 349/// 350///发送报文 351/// 352///报文 353publicvoidSend(byte[]datagram) 354{ 355if(datagram==null) 356thrownewArgumentNullException("datagram"); 357 358if(!Connected) 359{ 360RaiseServerDisconnected(Addresses,Port); 361thrownewInvalidProgramException( 362"Thisclienthasnotconnectedtoserver."); 363} 364 365tcpClient.GetStream().BeginWrite( 366datagram,0,datagram.Length,HandleDatagramWritten,tcpClient); 367} 368 369privatevoidHandleDatagramWritten(IAsyncResultar) 370{ 371((TcpClient)ar.AsyncState).GetStream().EndWrite(ar); 372} 373 374/// 375///发送报文 376/// 377///报文 378publicvoidSend(stringdatagram) 379{ 380Send(this.Encoding.GetBytes(datagram)); 381} 382 383#endregion 384 385#regionIDisposableMembers 386 387/// 388///Performsapplication-definedtasksassociatedwithfreeing, 389///releasing,orresettingunmanagedresources. 390/// 391publicvoidDispose() 392{ 393Dispose(true); 394GC.SuppressFinalize(this); 395} 396 397/// 398///Releasesunmanagedand-optionally-managedresources 399/// 400///truetoreleasebothmanaged 401///andunmanagedresources;false 402///toreleaseonlyunmanagedresources. 403/// 404protectedvirtualvoidDispose(booldisposing) 405{ 406if(!this.disposed) 407{ 408if(disposing) 409{ 410try 411{ 412Close(); 413 414if(tcpClient!=null) 415{ 416tcpClient=null; 417} 418} 419catch(SocketExceptionex) 420{ 421ExceptionHandler.Handle(ex); 422} 423} 424 425disposed=true; 426} 427} 428 429#endregion 430} 复制代码 使用举例 复制代码 1classProgram 2{ 3staticAsyncTcpClientclient; 4 5staticvoidMain(string[]args) 6{ 7LogFactory.Assign(newConsoleLogFactory()); 8 9//测试用,可以不指定由系统选择端口 10IPEndPointremoteEP=newIPEndPoint(IPAddress.Parse("127.0.0.1"),9999); 11IPEndPointlocalEP=newIPEndPoint(IPAddress.Parse("127.0.0.1"),9998); 12client=newAsyncTcpClient(remoteEP,localEP); 13client.www.wang027.comEncoding=Encoding.UTF8; 14client.ServerExceptionOccurred+= 15newEventHandler(client_ServerExceptionOccurred); 16client.ServerConnected+= 17newEventHandler(client_ServerConnected); 18client.ServerDisconnected+= 19newEventHandler(client_ServerDisconnected); 20client.PlaintextReceived+= 21newEventHandler>(client_PlaintextReceived); 22client.Connect(); 23 24Console.WriteLine("TCPclienthasconnectedtoserver."); 25Console.WriteLine("Typesomethingtosendtoserver..."); 26while(true) 27{ 28try 29{ 30stringtext=Console.ReadLine(); 31client.Send(text); 32} 33catch(Exceptionex) 34{ 35Console.WriteLine(ex.Message); 36} 37} 38} 39 40staticvoidclient_ServerExceptionOccurred( 41objectsender,TcpServerExceptionOccurredEventArgse) 42{ 43Logger.Debug(string.Format(CultureInfo.InvariantCulture, 44"TCPserver{0}exceptionoccurred,{1}.", 45e.ToString(),e.Exception.Message)); 46} 47 48staticvoidclient_ServerConnected( 49objectsender,TcpServerConnectedEventArgse) 50{ 51Logger.Debug(string.Format(CultureInfo.InvariantCulture, 52"TCPserver{0}hasconnected.",e.ToString())); 53} 54 55staticvoidclient_ServerDisconnected( 56objectsender,TcpServerDisconnectedEventArgse) 57{ 58Logger.Debug(string.Format(CultureInfo.InvariantCulture, 59"TCPserver{0}hasdisconnected.",e.ToString())); 60} 61 62staticvoidclient_PlaintextReceived( 63objectsender,TcpDatagramReceivedEventArgse) 64{ 65Console.Write(string.Format("Server:{0}-->", 66e.TcpClient.Client.RemoteEndPoint.ToString())); 67Console.WriteLine(string.Format("{0}",e.Datagram)); 68} 69} 复制代码 TCP客户端State 复制代码 1/// 2///InternalclasstojointheTCPclientandbuffertogether 3///foreasymanagementintheserver 4/// 5internalclassTcpClientState 6{ 7/// 8///ConstructorforanewClient 9/// 10///TheTCPclient 11///Thebytearraybuffer 12publicTcpClientState(TcpClienttcpClient,byte[]buffer) 13{ 14if(tcpClient==null) 15thrownewArgumentNullException("tcpClient"); 16if(buffer==null) 17thrownewArgumentNullException("buffer"); 18 19this.TcpClient=tcpClient; 20this.Buffer=buffer; 21} 22 23/// 24///GetstheTCPClient 25/// 26publicTcpClientTcpClient{get;privateset;} 27 28/// 29///GetstheBuffer. 30/// 31publicbyte[]Buffer{get;privateset;} 32 33/// 34///Getsthenetworkstream 35/// 36publicNetworkStreamNetworkStream 37{ 38get{returnTcpClient.GetStream();} 39} 40} 复制代码 与客户端的连接已建立事件参数 复制代码 1/// 2///与客户端的连接已建立事件参数 3/// 4publicclassTcpClientConnectedEventArgs:EventArgs 5{ 6/// 7///与客户端的连接已建立事件参数 8/// 9///客户端 10publicTcpClientConnectedEventArgs(TcpClienttcpClient) 11{ 12if(tcpClient==null) 13thrownewArgumentNullException("tcpClient"); 14 15this.TcpClient=tcpClient; 16} 17 18/// 19///客户端 20/// 21publicTcpClientTcpClient{get;privateset;} 22} 复制代码 与客户端的连接已断开事件参数 复制代码 /// ///与客户端的连接已断开事件参数 /// publicclassTcpClientDisconnectedEventArgs:EventArgs { /// ///与客户端的连接已断开事件参数 /// ///客户端 publicTcpClientDisconnectedEventArgs(TcpClienttcpClient) { if(tcpClient==null) thrownewArgumentNullException("tcpClient");
this.TcpClient=tcpClient; }
/// ///客户端 /// publicTcpClientTcpClient{get;privateset;} } 复制代码 与服务器的连接发生异常事件参数 复制代码 1/// 2///与服务器的连接发生异常事件参数 3/// 4publicclassTcpServerExceptionOccurredEventArgs:EventArgs 5{ 6/// 7///与服务器的连接发生异常事件参数 8/// 9///服务器IP地址列表 10///服务器端口 11///内部异常 12publicTcpServerExceptionOccurredEventArgs( 13IPAddress[]ipAddresses,intport,ExceptioninnerException) 14{ 15if(ipAddresses==null) 16thrownewArgumentNullException("ipAddresses"); 17 18this.Addresses=ipAddresses; 19this.Port=port; 20this.Exception=innerException; 21} 22 23/// 24///服务器IP地址列表 25/// 26publicIPAddress[]Addresses{get;privateset;} 27/// 28///服务器端口 29/// 30publicintPort{get;privateset;} 31/// 32///内部异常 33/// 34publicExceptionException{get;privateset;} 35 36/// 37///Returnsathatrepresentsthisinstance. 38/// 39/// 40///Athatrepresentsthisinstance. 41/// 42publicoverridestringToString() 43{ 44strings=string.Empty; 45foreach(variteminAddresses) 46{ 47s=s+item.ToString()+'',''; 48} 49s=s.TrimEnd('',''); 50s=s+":"+Port.ToString(CultureInfo.InvariantCulture); 51 52returns; 53} 54} 复制代码 接收到数据报文事件参数 复制代码 1/// 2///接收到数据报文事件参数 3/// 4///报文类型 5publicclassTcpDatagramReceivedEventArgs:EventArgs 6{ 7/// 8///接收到数据报文事件参数 9/// 10///客户端 11///报文 12publicTcpDatagramReceivedEventArgs(TcpClienttcpClient,Tdatagram) 13{ 14TcpClient=tcpClient; 15Datagram=datagram; 16} 17 18/// 19///客户端 20/// 21publicTcpClientTcpClient{get;privateset;} 22/// 23///报文 24/// 25publicTDatagram{get;privateset;} 26} 复制代码 与服务器的连接已建立事件参数 复制代码 1/// 2///与服务器的连接已建立事件参数 3/// 4publicclassTcpServerConnectedEventArgs:EventArgs 5{ 6/// 7///与服务器的连接已建立事件参数 8/// 9///服务器IP地址列表 10///服务器端口 11publicTcpServerConnectedEventArgs(IPAddress[]ipAddresses,intport) 12{ 13if(ipAddresses==null) 14thrownewArgumentNullException("ipAddresses"); 15 16this.Addresses=ipAddresses; 17this.Port=port; 18} 19 20/// 21///服务器IP地址列表 22/// 23publicIPAddress[]Addresses{get;privateset;} 24/// 25///服务器端口 26/// 27publicintPort{get;privateset;} 28 29/// 30///Returnsathatrepresentsthisinstance. 31/// 32/// 33///Athatrepresentsthisinstance. 34/// 35publicoverridestringToString() 36{ 37strings=string.Empty; 38foreach(variteminAddresses) 39{ 40s=s+item.ToString()+'',''; 41} 42s=s.TrimEnd('',''); 43s=s+":"+Port.ToString(CultureInfo.InvariantCulture); 44 45returns; 46} 47} 复制代码 与服务器的连接已断开事件参数 复制代码 1/// 2///与服务器的连接已断开事件参数 3/// 4publicclassTcpServerDisconnectedEventArgs:EventArgs 5{ 6/// 7///与服务器的连接已断开事件参数 8/// 9///服务器IP地址列表 10///服务器端口 11publicTcpServerDisconnectedEventArgs(IPAddress[]ipAddresses,intport) 12{ 13if(ipAddresses==null) 14thrownewArgumentNullException("ipAddresses"); 15 16this.Addresses=ipAddresses; 17this.Port=port; 18} 19 20/// 21///服务器IP地址列表 22/// 23publicIPAddress[]Addresses{get;privateset;} 24/// 25///服务器端口 26/// 27publicintPort{get;privateset;} 28 29/// 30///Returnsathatrepresentsthisinstance. 31/// 32/// 33///Athatrepresentsthisinstance. 34/// 35publicoverridestringToString() 36{ 37strings=string.Empty; 38foreach(variteminAddresses) 39{ 40s=s+item.ToString()+'',''; 41} 42s=s.TrimEnd('',''); 43s=s+":"+Port.ToString(CultureInfo.InvariantCulture); 44 45returns; 46} 47} |
|