好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

C#异步TCP服务器完整实现

C#异步TCP服务器完整实现

C#异步TCP服务器完整实现

TCP异步Socket模型

C#的TCP异步Socket模型是通过Begin-End模式实现的。例如提供 BeginConnect 、 BeginAccept、   BeginSend  和  BeginReceive等。

IAsyncResult BeginAccept(AsyncCallback callback,  object  state);

Async Callback 回调在函数执行完毕后执行。state对象被用于在执行函数和回调函数间传输信息。

Socket socket =  new   Socket(
                  AddressFamily.InterNetwork, 
                  SocketType.Stream, 
                  ProtocolType.Tcp);
IPEndPoint iep  =  new  IPEndPoint(IPAddress.Any,  8888  );
socket.Bind(iep);
socket.Listen(  5  );
socket.BeginAccept (  new   AsyncCallback(CallbackAccept), socket);

  private   void   CallbackAccept(IAsyncResult iar)
{
  Socket server  =  (Socket)iar.AsyncState;
  Socket client  =  server.EndAccept(iar);
} 

则在Accept一个TcpClient,需要维护TcpClient列表。

 private  List<TcpClientState> clients;

异步TCP服务器完整实现

   1     ///   <summary> 
   2     ///   异步TCP服务器
    3     ///   </summary> 
   4     public   class   AsyncTcpServer : IDisposable
    5     {
    6       #region  Fields
   7  
   8       private   TcpListener listener;
    9       private  List<TcpClientState>  clients;
   10       private   bool  disposed =  false  ;
   11  
  12       #endregion 
  13  
  14       #region  Ctors
  15  
  16       ///   <summary> 
  17       ///   异步TCP服务器
   18       ///   </summary> 
  19       ///   <param name="listenPort">  监听的端口  </param> 
  20       public  AsyncTcpServer( int   listenPort)
   21        :  this  (IPAddress.Any, listenPort)
   22       {
   23       }
   24  
  25       ///   <summary> 
  26       ///   异步TCP服务器
   27       ///   </summary> 
  28       ///   <param name="localEP">  监听的终结点  </param> 
  29       public   AsyncTcpServer(IPEndPoint localEP)
   30        :  this  (localEP.Address, localEP.Port)
   31       {
   32       }
   33  
  34       ///   <summary> 
  35       ///   异步TCP服务器
   36       ///   </summary> 
  37       ///   <param name="localIPAddress">  监听的IP地址  </param> 
  38       ///   <param name="listenPort">  监听的端口  </param> 
  39       public  AsyncTcpServer(IPAddress localIPAddress,  int   listenPort)
   40       {
   41        Address =  localIPAddress;
   42        Port =  listenPort;
   43         this .Encoding =  Encoding.Default;
   44  
  45        clients =  new  List<TcpClientState> ();
   46  
  47        listener =  new   TcpListener(Address, Port);
   48        listener.AllowNatTraversal( true  );
   49       }
   50  
  51       #endregion 
  52  
  53       #region  Properties
  54  
  55       ///   <summary> 
  56       ///   服务器是否正在运行
   57       ///   </summary> 
  58       public   bool  IsRunning {  get ;  private   set  ; }
   59       ///   <summary> 
  60       ///   监听的IP地址
   61       ///   </summary> 
  62       public  IPAddress Address {  get ;  private   set  ; }
   63       ///   <summary> 
  64       ///   监听的端口
   65       ///   </summary> 
  66       public   int  Port {  get ;  private   set  ; }
   67       ///   <summary> 
  68       ///   通信使用的编码
   69       ///   </summary> 
  70       public  Encoding Encoding {  get ;  set  ; }
   71  
  72       #endregion 
  73  
  74       #region  Server
  75  
  76       ///   <summary> 
  77       ///   启动服务器
   78       ///   </summary> 
  79       ///   <returns>  异步TCP服务器  </returns> 
  80       public   AsyncTcpServer Start()
   81       {
   82         if  (! IsRunning)
   83         {
   84          IsRunning =  true  ;
   85           listener.Start();
   86           listener.BeginAcceptTcpClient(
   87             new   AsyncCallback(HandleTcpClientAccepted), listener);
   88         }
   89         return   this  ;
   90       }
   91  
  92       ///   <summary> 
  93       ///   启动服务器
   94       ///   </summary> 
  95       ///   <param name="backlog"> 
  96       ///   服务器所允许的挂起连接序列的最大长度
   97       ///   </param> 
  98       ///   <returns>  异步TCP服务器  </returns> 
  99       public  AsyncTcpServer Start( int   backlog)
  100       {
  101         if  (! IsRunning)
  102         {
  103          IsRunning =  true  ;
  104           listener.Start(backlog);
  105           listener.BeginAcceptTcpClient(
  106             new   AsyncCallback(HandleTcpClientAccepted), listener);
  107         }
  108         return   this  ;
  109       }
  110  
 111       ///   <summary> 
 112       ///   停止服务器
  113       ///   </summary> 
 114       ///   <returns>  异步TCP服务器  </returns> 
 115       public   AsyncTcpServer Stop()
  116       {
  117         if   (IsRunning)
  118         {
  119          IsRunning =  false  ;
  120           listener.Stop();
  121  
 122           lock  ( this  .clients)
  123           {
  124             for  ( int  i =  0 ; i <  this .clients.Count; i++ )
  125             {
  126               this .clients[i].TcpClient.Client.Disconnect( false  );
  127             }
  128             this  .clients.Clear();
  129           }
  130  
 131         }
  132         return   this  ;
  133       }
  134  
 135       #endregion 
 136  
 137       #region  Receive
 138  
 139       private   void   HandleTcpClientAccepted(IAsyncResult ar)
  140       {
  141         if   (IsRunning)
  142         {
  143          TcpListener tcpListener =  (TcpListener)ar.AsyncState;
  144  
 145          TcpClient tcpClient =  tcpListener.EndAcceptTcpClient(ar);
  146           byte [] buffer =  new   byte  [tcpClient.ReceiveBufferSize];
  147  
 148           TcpClientState internalClient 
  149            =  new   TcpClientState(tcpClient, buffer);
  150           lock  ( this  .clients)
  151           {
  152             this  .clients.Add(internalClient);
  153             RaiseClientConnected(tcpClient);
  154           }
  155  
 156          NetworkStream networkStream =  internalClient.NetworkStream;
  157           networkStream.BeginRead(
  158             internalClient.Buffer, 
  159             0  , 
  160             internalClient.Buffer.Length, 
  161             HandleDatagramReceived, 
  162             internalClient);
  163  
 164           tcpListener.BeginAcceptTcpClient(
  165             new   AsyncCallback(HandleTcpClientAccepted), ar.AsyncState);
  166         }
  167       }
  168  
 169       private   void   HandleDatagramReceived(IAsyncResult ar)
  170       {
  171         if   (IsRunning)
  172         {
  173          TcpClientState internalClient =  (TcpClientState)ar.AsyncState;
  174          NetworkStream networkStream =  internalClient.NetworkStream;
  175  
 176           int  numberOfReadBytes =  0  ;
  177           try 
 178           {
  179            numberOfReadBytes =  networkStream.EndRead(ar);
  180           }
  181           catch 
 182           {
  183            numberOfReadBytes =  0  ;
  184           }
  185  
 186           if  (numberOfReadBytes ==  0  )
  187           {
  188             //   connection has been closed 
 189             lock  ( this  .clients)
  190             {
  191               this  .clients.Remove(internalClient);
  192               RaiseClientDisconnected(internalClient.TcpClient);
  193               return  ;
  194             }
  195           }
  196  
 197           //   received byte and trigger event notification 
 198           byte [] receivedBytes =  new   byte  [numberOfReadBytes];
  199           Buffer.BlockCopy(
  200            internalClient.Buffer,  0  , 
  201            receivedBytes,  0  , numberOfReadBytes);
  202           RaiseDatagramReceived(internalClient.TcpClient, receivedBytes);
  203           RaisePlaintextReceived(internalClient.TcpClient, receivedBytes);
  204  
 205           //   continue listening for tcp datagram packets 
 206           networkStream.BeginRead(
  207             internalClient.Buffer, 
  208             0  , 
  209             internalClient.Buffer.Length, 
  210             HandleDatagramReceived, 
  211             internalClient);
  212         }
  213       }
  214  
 215       #endregion 
 216  
 217       #region  Events
 218  
 219       ///   <summary> 
 220       ///   接收到数据报文事件
  221       ///   </summary> 
 222       public   event  EventHandler<TcpDatagramReceivedEventArgs< byte []>>  DatagramReceived;
  223       ///   <summary> 
 224       ///   接收到数据报文明文事件
  225       ///   </summary> 
 226       public   event  EventHandler<TcpDatagramReceivedEventArgs< string >>  PlaintextReceived;
  227  
 228       private   void  RaiseDatagramReceived(TcpClient sender,  byte  [] datagram)
  229       {
  230         if  (DatagramReceived !=  null  )
  231         {
  232          DatagramReceived( this ,  new  TcpDatagramReceivedEventArgs< byte []> (sender, datagram));
  233         }
  234       }
  235  
 236       private   void  RaisePlaintextReceived(TcpClient sender,  byte  [] datagram)
  237       {
  238         if  (PlaintextReceived !=  null  )
  239         {
  240          PlaintextReceived( this ,  new  TcpDatagramReceivedEventArgs< string > (
  241            sender,  this .Encoding.GetString(datagram,  0  , datagram.Length)));
  242         }
  243       }
  244  
 245       ///   <summary> 
 246       ///   与客户端的连接已建立事件
  247       ///   </summary> 
 248       public   event  EventHandler<TcpClientConnectedEventArgs>  ClientConnected;
  249       ///   <summary> 
 250       ///   与客户端的连接已断开事件
  251       ///   </summary> 
 252       public   event  EventHandler<TcpClientDisconnectedEventArgs>  ClientDisconnected;
  253  
 254       private   void   RaiseClientConnected(TcpClient tcpClient)
  255       {
  256         if  (ClientConnected !=  null  )
  257         {
  258          ClientConnected( this ,  new   TcpClientConnectedEventArgs(tcpClient));
  259         }
  260       }
  261  
 262       private   void   RaiseClientDisconnected(TcpClient tcpClient)
  263       {
  264         if  (ClientDisconnected !=  null  )
  265         {
  266          ClientDisconnected( this ,  new   TcpClientDisconnectedEventArgs(tcpClient));
  267         }
  268       }
  269  
 270       #endregion 
 271  
 272       #region  Send
 273  
 274       ///   <summary> 
 275       ///   发送报文至指定的客户端
  276       ///   </summary> 
 277       ///   <param name="tcpClient">  客户端  </param> 
 278       ///   <param name="datagram">  报文  </param> 
 279       public   void  Send(TcpClient tcpClient,  byte  [] datagram)
  280       {
  281         if  (! IsRunning)
  282           throw   new  InvalidProgramException( "  This TCP server has not been started.  "  );
  283  
 284         if  (tcpClient ==  null  )
  285           throw   new  ArgumentNullException( "  tcpClient  "  );
  286  
 287         if  (datagram ==  null  )
  288           throw   new  ArgumentNullException( "  datagram  "  );
  289  
 290         tcpClient.GetStream().BeginWrite(
  291          datagram,  0  , datagram.Length, HandleDatagramWritten, tcpClient);
  292       }
  293  
 294       private   void   HandleDatagramWritten(IAsyncResult ar)
  295       {
  296         ((TcpClient)ar.AsyncState).GetStream().EndWrite(ar);
  297       }
  298  
 299       ///   <summary> 
 300       ///   发送报文至指定的客户端
  301       ///   </summary> 
 302       ///   <param name="tcpClient">  客户端  </param> 
 303       ///   <param name="datagram">  报文  </param> 
 304       public   void  Send(TcpClient tcpClient,  string   datagram)
  305       {
  306        Send(tcpClient,  this  .Encoding.GetBytes(datagram));
  307       }
  308  
 309       ///   <summary> 
 310       ///   发送报文至所有客户端
  311       ///   </summary> 
 312       ///   <param name="datagram">  报文  </param> 
 313       public   void  SendAll( byte  [] datagram)
  314       {
  315         if  (! IsRunning)
  316           throw   new  InvalidProgramException( "  This TCP server has not been started.  "  );
  317  
 318         for  ( int  i =  0 ; i <  this .clients.Count; i++ )
  319         {
  320          Send( this  .clients[i].TcpClient, datagram);
  321         }
  322       }
  323  
 324       ///   <summary> 
 325       ///   发送报文至所有客户端
  326       ///   </summary> 
 327       ///   <param name="datagram">  报文  </param> 
 328       public   void  SendAll( string   datagram)
  329       {
  330         if  (! IsRunning)
  331           throw   new  InvalidProgramException( "  This TCP server has not been started.  "  );
  332  
 333        SendAll( this  .Encoding.GetBytes(datagram));
  334       }
  335  
 336       #endregion 
 337  
 338       #region  IDisposable Members
 339  
 340       ///   <summary> 
 341       ///   Performs application-defined tasks associated with freeing, 
  342       ///   releasing, or resetting unmanaged resources.
  343       ///   </summary> 
 344       public   void   Dispose()
  345       {
  346        Dispose( true  );
  347        GC.SuppressFinalize( this  );
  348       }
  349  
 350       ///   <summary> 
 351       ///   Releases unmanaged and - optionally - managed resources
  352       ///   </summary> 
 353       ///   <param name="disposing"><c>  true  </c>   to release 
  354       ///   both managed and unmanaged resources;   <c>  false  </c>  
 355       ///   to release only unmanaged resources.  </param> 
 356       protected   virtual   void  Dispose( bool   disposing)
  357       {
  358         if  (! this  .disposed)
  359         {
  360           if   (disposing)
  361           {
  362             try 
 363             {
  364               Stop();
  365  
 366               if  (listener !=  null  )
  367               {
  368                listener =  null  ;
  369               }
  370             }
  371             catch   (SocketException ex)
  372             {
  373               ExceptionHandler.Handle(ex);
  374             }
  375           }
  376  
 377          disposed =  true  ;
  378         }
  379       }
  380  
 381       #endregion 
 382    }

使用举例

  1     class   Program
   2     {
   3       static   AsyncTcpServer server;
   4  
  5       static   void  Main( string  [] args)
   6       {
   7        LogFactory.Assign( new   ConsoleLogFactory());
   8  
  9        server =  new  AsyncTcpServer( 9999  );
  10        server.Encoding =  Encoding.UTF8;
  11        server.ClientConnected += 
 12           new  EventHandler<TcpClientConnectedEventArgs> (server_ClientConnected);
  13        server.ClientDisconnected += 
 14           new  EventHandler<TcpClientDisconnectedEventArgs> (server_ClientDisconnected);
  15        server.PlaintextReceived += 
 16           new  EventHandler<TcpDatagramReceivedEventArgs< string >> (server_PlaintextReceived);
  17         server.Start();
  18  
 19        Console.WriteLine( "  TCP server has been started.  "  );
  20        Console.WriteLine( "  Type something to send to client...  "  );
  21         while  ( true  )
  22         {
  23           string  text =  Console.ReadLine();
  24           server.SendAll(text);
  25         }
  26       }
  27  
 28       static   void  server_ClientConnected( object   sender, TcpClientConnectedEventArgs e)
  29       {
  30        Logger.Debug( string  .Format(CultureInfo.InvariantCulture, 
  31           "  TCP client {0} has connected.  "  , 
  32           e.TcpClient.Client.RemoteEndPoint.ToString()));
  33       }
  34  
 35       static   void  server_ClientDisconnected( object   sender, TcpClientDisconnectedEventArgs e)
  36       {
  37        Logger.Debug( string  .Format(CultureInfo.InvariantCulture, 
  38           "  TCP client {0} has disconnected.  "  , 
  39           e.TcpClient.Client.RemoteEndPoint.ToString()));
  40       }
  41  
 42       static   void  server_PlaintextReceived( object  sender, TcpDatagramReceivedEventArgs< string >  e)
  43       {
  44         if  (e.Datagram !=  "  Received  "  )
  45         {
  46          Console.Write( string .Format( "  Client : {0} -->   "  , 
  47             e.TcpClient.Client.RemoteEndPoint.ToString()));
  48          Console.WriteLine( string .Format( "  {0}  "  , e.Datagram));
  49          server.Send(e.TcpClient,  "  Server has received you text :   "  +  e.Datagram);
  50         }
  51       }
  52    }

 

 

 

标签:  C# ,  .NET ,  TCP

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于C#异步TCP服务器完整实现的详细内容...

  阅读:39次