1. 程式人生 > >C#非同步TCP伺服器完整實現

C#非同步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