.NET下可复用的TCP通信层实现之TCP组件(5)
点击次数:16 次 发布日期:2008-11-26 12:27:46 作者:源代码网
|
源代码网推荐 源代码网推荐 这种方式的主要思想是:当一个新的Tcp连接建立时,就在该连接上发送一个异步接收的请求(BeginRead),并在异步回调中处理该请求,当请求处理完毕,再次发送异步接收请求,如此循环下去。异步接收启用的是系统默认线程池中的线程,所以,在异步Tcp组件中不用显式管理工作线程。异步Tcp组件的实现相对于完成端口模型而言简单许多,也单纯一些,不用管理请求队列,不需使用工作者线程等等。但是,相比于完成端口模型,其也有明显的缺陷:一个Tcp连接绑定到了一个线程,即使这个线程是后台线程池中的。如果用户数量巨大,这对性能是极其不利的;而完成端口模型,则可以限定工作者线程的个数,并且可以根据应用的类型进行灵活调节。 源代码网推荐 源代码网推荐 异步Tcp组件实现源码。 源代码网推荐 源代码网推荐 异步Tcp组件 源代码网推荐 源代码网推荐 1/**//// <summary> 源代码网推荐 2 /// AsynTcp 异步Tcp组件。 源代码网推荐 3 /// </summary> 源代码网推荐 4 public class AsynTcp :ITcp 源代码网推荐 5 { 源代码网推荐 6 members#region members 源代码网推荐 7 private const int BufferSize = 1024 ; 源代码网推荐 8 源代码网推荐 9 private IXTcpListener xtcpListener = null ; 源代码网推荐 10 private ITcpReqStreamDispatcher messageDispatcher = null ; 源代码网推荐 11 private ContextKeyManager contextKeyMgr = new ContextKeyManager() ; 源代码网推荐 12 private bool stateIsStop = true ; 源代码网推荐 13 private bool validateRequest = false ; 源代码网推荐 14 private int curPort = 8888 ; 源代码网推荐 15 #endregion 源代码网推荐 16 源代码网推荐 17 源代码网推荐 18 public AsynTcp() 源代码网推荐 19 { 源代码网推荐 20 源代码网推荐 21 } 源代码网推荐 22 源代码网推荐 23 INet 成员#region INet 成员 源代码网推荐 24 源代码网推荐 25 public event CallBackDynamicMessage DynamicMsgArrived; 源代码网推荐 26 源代码网推荐 27 public NetAddinType GetProtocalType() 源代码网推荐 28 { 源代码网推荐 29 源代码网推荐 30 return NetAddinType.Tcp; 源代码网推荐 31 } 源代码网推荐 32 源代码网推荐 33 InitializeAll ,UnitializeAll#region InitializeAll ,UnitializeAll 源代码网推荐 34 public void InitializeAll(IReqestStreamDispatcher i_dispatcher, int port, bool userValidated) 源代码网推荐 35 { 源代码网推荐 36 this.messageDispatcher = i_dispatcher as ITcpReqStreamDispatcher; 源代码网推荐 37 if(this.messageDispatcher == null) 源代码网推荐 38 { 源代码网推荐 39 throw new Exception("Can"t convert IReqestStreamDispatcher to ITcpReqStreamDispatcher in CompletePortManager.InitializeAll method ! ") ; 源代码网推荐 40 } 源代码网推荐 41 源代码网推荐 42 this.curPort = port ; 源代码网推荐 43 this.validateRequest = userValidated ; 源代码网推荐 44 源代码网推荐 45 this.InitializeAll() ; 源代码网推荐 46 } 源代码网推荐 47 源代码网推荐 48 public void InitializeAll() 源代码网推荐 49 { 源代码网推荐 50 this.xtcpListener = new XTcpListener(this.curPort) ; 源代码网推荐 51 this.xtcpListener.TcpConnectionEstablished += new CBackUserLogon(xtcpListener_TcpConnectionEstablished); 源代码网推荐 52 this.xtcpListener.DynamicMsgArrived += new CallBackDynamicMsg(this.PutoutDynamicMsg) ; 源代码网推荐 53 this.contextKeyMgr.StreamCountChanged += new CallBackCountChanged(this.OnStreamCountChanged) ; 源代码网推荐 54 } 源代码网推荐 55 源代码网推荐 56 public void UnitializeAll() 源代码网推荐 57 { 源代码网推荐 58 this.Stop() ; 源代码网推荐 59 this.xtcpListener.ExitListenThread() ; 源代码网推荐 60 源代码网推荐 61 //将事件容器清空==》防止外部框架再多次初始化的过程中将一个事件预定多次 源代码网推荐 62 this.ConnectionCountChanged = null ; 源代码网推荐 63 this.DynamicMsgArrived = null ; 源代码网推荐 64 this.ServiceCommitted = null ; 源代码网推荐 65 this.SomeOneConnected = null ; 源代码网推荐 66 this.SomeOneDisConnected = null ; 源代码网推荐 67 this.UserAction = null ; 源代码网推荐 68 } 源代码网推荐 69 源代码网推荐 70 #endregion 源代码网推荐 71 源代码网推荐 72 Start ,Stop#region Start ,Stop 源代码网推荐 73 public void Start() 源代码网推荐 74 { 源代码网推荐 75 if(this.stateIsStop) 源代码网推荐 76 { 源代码网推荐 77 this.xtcpListener.Start() ; 源代码网推荐 78 this.stateIsStop = false ; 源代码网推荐 79 } 源代码网推荐 80 } 源代码网推荐 81 源代码网推荐 82 public void Stop() 源代码网推荐 83 { 源代码网推荐 84 if(this.stateIsStop) 源代码网推荐 85 { 源代码网推荐 86 return ; 源代码网推荐 87 } 源代码网推荐 88 源代码网推荐 89 this.stateIsStop = true ; 源代码网推荐 90 this.xtcpListener.Stop() ; 源代码网推荐 91 源代码网推荐 92 //关闭所有连接 源代码网推荐 93 int count = 0 ; 源代码网推荐 94 while(! this.contextKeyMgr.IsAllStreamSafeToStop()) //等待所有流到达停止安全点 源代码网推荐 95 { 源代码网推荐 96 Thread.Sleep(200) ; 源代码网推荐 97 if(10 == count++) 源代码网推荐 98 { 源代码网推荐 99 break ; 源代码网推荐 100 } 源代码网推荐 101 } 源代码网推荐 102 this.contextKeyMgr.DisposeAllContextKey() ; 源代码网推荐 103 } 源代码网推荐 104 #endregion 源代码网推荐 105 源代码网推荐 106 #endregion 源代码网推荐 107 源代码网推荐 108 ITcpEventList 成员#region ITcpEventList 成员 源代码网推荐 109 源代码网推荐 110 public event EnterpriseServerBase.Network.CallBackForTcpUser2 SomeOneConnected; 源代码网推荐 111 源代码网推荐 112 public event EnterpriseServerBase.Network.CallBackForTcpMonitor ServiceCommitted; 源代码网推荐 113 源代码网推荐 114 public event EnterpriseServerBase.Network.CallBackForTcpCount ConnectionCountChanged; 源代码网推荐 115 源代码网推荐 116 public event EnterpriseServerBase.Network.CallBackForTcpUser1 SomeOneDisConnected; 源代码网推荐 117 源代码网推荐 118 public event EnterpriseServerBase.Network.CallBackForTcpUser UserAction; 源代码网推荐 119 源代码网推荐 120 #endregion 源代码网推荐 121 源代码网推荐 122 ITcpClientsController 成员#region ITcpClientsController 成员 源代码网推荐 123 源代码网推荐 124 public bool SynRecieveFrom(int ConnectID ,byte[] buffer, int offset, int size ,out int readCount) 源代码网推荐 125 { 源代码网推荐 126 readCount = 0 ; 源代码网推荐 127 ISafeNetworkStream netStream = this.contextKeyMgr.GetNetStream(ConnectID) ; 源代码网推荐 128 if(netStream == null) 源代码网推荐 129 { 源代码网推荐 130 return false ; 源代码网推荐 131 } 源代码网推荐 132 源代码网推荐 133 readCount = netStream.Read(buffer ,offset ,size) ; 源代码网推荐 134 源代码网推荐 135 return true ; 源代码网推荐 136 } 源代码网推荐 137 源代码网推荐 138 public void SendData(int ConnectID, byte[] data) 源代码网推荐 139 { 源代码网推荐 140 this.SendData(ConnectID ,data ,0 ,data.Length) ; 源代码网推荐 141 } 源代码网推荐 142 源代码网推荐 143 public void SendData(int ConnectID, byte[] data ,int offset ,int size) 源代码网推荐 144 { 源代码网推荐 145 if((data == null) || (data.Length == 0) || (offset <0) ||(size <0) || (offset+size > data.Length)) 源代码网推荐 146 { 源代码网推荐 147 return ; 源代码网推荐 148 } 源代码网推荐 149 源代码网推荐 150 ISafeNetworkStream netStream = this.contextKeyMgr.GetNetStream(ConnectID) ; 源代码网推荐 151 if(netStream == null) 源代码网推荐 152 { 源代码网推荐 153 return ; 源代码网推荐 154 } 源代码网推荐 155 源代码网推荐 156 netStream.Write(data ,offset ,size) ; 源代码网推荐 157 } 源代码网推荐 158 源代码网推荐 159 public void DisposeOneConnection(int connectID, DisconnectedCause cause) 源代码网推荐 160 { 源代码网推荐 161 this.DisposeOneConnection(connectID) ; 源代码网推荐 162 源代码网推荐 163 if(this.SomeOneDisConnected != null) 源代码网推荐 164 { 源代码网推荐 165 this.SomeOneDisConnected(connectID , cause) ; 源代码网推荐 166 } 源代码网推荐 167 源代码网推荐 168 this.ActivateUserActionEvent(connectID ,TcpUserAction.Exit) ; 源代码网推荐 169 } 源代码网推荐 170 源代码网推荐 171 #endregion 源代码网推荐 172 源代码网推荐 173 ITcp 成员#region ITcp 成员 源代码网推荐 174 public int ConnectionCount 源代码网推荐 175 { 源代码网推荐 176 get 源代码网推荐 177 { 源代码网推荐 178 return this.contextKeyMgr.ConnectionCount ; 源代码网推荐 179 } 源代码网推荐 180 } 源代码网推荐 181 源代码网推荐 182 #endregion 源代码网推荐 183 源代码网推荐 184 private#region private 源代码网推荐 185 源代码网推荐 186 ActivateUserActionEvent#region ActivateUserActionEvent 源代码网推荐 187 private void ActivateUserActionEvent(int ConnectID ,TcpUserAction action) 源代码网推荐 188 { 源代码网推荐 189 if(this.UserAction != null) 源代码网推荐 190 { 源代码网推荐 191 this.UserAction(ConnectID ,action) ; 源代码网推荐 192 } 源代码网推荐 193 } 源代码网推荐 194 #endregion 源代码网推荐 195 源代码网推荐 196 DisposeOneConnection#region DisposeOneConnection 源代码网推荐 197 /**//// <summary> 源代码网推荐 198 /// DisposeOneConnection 主要由用户管理模块调用--当无法检测到掉线情况时,该方法保证资源被释放 源代码网推荐 199 /// </summary> 源代码网推荐 200 private void DisposeOneConnection(int connectID) 源代码网推荐 201 { 源代码网推荐 202 this.contextKeyMgr.RemoveContextKey(connectID) ; 源代码网推荐 203 } 源代码网推荐 204 #endregion 源代码网推荐 205 源代码网推荐 206 xtcpListener_TcpConnectionEstablished#region xtcpListener_TcpConnectionEstablished 源代码网推荐 207 private void xtcpListener_TcpConnectionEstablished(NetworkStream stream) 源代码网推荐 208 { 源代码网推荐 209 ISafeNetworkStream safeStream = new SafeNetworkStream(stream) ; 源代码网推荐 210 源代码网推荐 211 ContextKey key = new ContextKey(safeStream ,AsynTcp.BufferSize) ; 源代码网推荐 212 key.ResetBuffer(null) ; 源代码网推荐 213 this.contextKeyMgr.InsertContextKey(key) ; 源代码网推荐 214 int connectID = key.NetStream.GetHashCode() ; 源代码网推荐 215 源代码网推荐 216 if(this.SomeOneConnected != null) 源代码网推荐 217 { 源代码网推荐 218 this.SomeOneConnected(connectID) ; 源代码网推荐 219 } 源代码网推荐 220 this.ActivateUserActionEvent(connectID ,TcpUserAction.Logon) ; 源代码网推荐 221 源代码网推荐 222 key.IsFirstMsg = true ; 源代码网推荐 223 this.RecieveDataFrom(key) ; 源代码网推荐 224 } 源代码网推荐 225 #endregion 源代码网推荐 226 源代码网推荐 227 PutoutDynamicMsg#region PutoutDynamicMsg 源代码网推荐 228 private void PutoutDynamicMsg(string msg) 源代码网推荐 229 { 源代码网推荐 230 if(this.DynamicMsgArrived != null) 源代码网推荐 231 { 源代码网推荐 232 this.DynamicMsgArrived(msg) ; 源代码网推荐 233 } 源代码网推荐 234 } 源代码网推荐 235 #endregion 源代码网推荐 236 源代码网推荐 237 OnStreamCountChanged#region OnStreamCountChanged 源代码网推荐 238 private void OnStreamCountChanged(int count) 源代码网推荐 239 { 源代码网推荐 240 if(this.ConnectionCountChanged != null) 源代码网推荐 241 { 源代码网推荐 242 this.ConnectionCountChanged(count) ; 源代码网推荐 243 } 源代码网推荐 244 } 源代码网推荐 245 #endregion 源代码网推荐 246 源代码网推荐 247 RecieveDataFrom#region RecieveDataFrom 源代码网推荐 248 private void RecieveDataFrom(ContextKey key) 源代码网推荐 249 { 源代码网推荐 250 key.StreamState = NetStreamState.Reading ; 源代码网推荐 251 key.NetStream.BeginRead(key.Buffer ,key.StartOffsetForRecieve ,key.MaxRecieveCapacity ,new AsyncCallback(this.ServeOverLap) ,key) ; 源代码网推荐 252 源代码网推荐 253 } 源代码网推荐 254 #endregion 源代码网推荐 255 源代码网推荐 256 ServeOverLap#region ServeOverLap 源代码网推荐 257 private void ServeOverLap(IAsyncResult ar) 源代码网推荐 258 { 源代码网推荐 259 ContextKey key = (ContextKey)ar.AsyncState ; 源代码网推荐 260 int streamHashCode = key.NetStream.GetHashCode() ; //是SafeNetworkStream的hashcode 源代码网推荐 261 源代码网推荐 262 try 源代码网推荐 263 { 源代码网推荐 264 key.BytesRead = key.NetStream.EndRead(ar) ; 源代码网推荐 265 源代码网推荐 266 if(! this.CheckData(key)) 源代码网推荐 267 { 源代码网推荐 268 return ; 源代码网推荐 269 } 源代码网推荐 270 源代码网推荐 271 //处理请求 源代码网推荐 272 byte[] leftData = null ; 源代码网推荐 273 ArrayList repondList = this.messageDispatcher.DealRequestMessage(key.RequestData ,out leftData , ref key.Validation) ; 源代码网推荐 274 源代码网推荐 275 if(this.validateRequest) 源代码网推荐 276 { 源代码网推荐 277 if(key.Validation.gotoCloseConnection) 源代码网推荐 278 { 源代码网推荐 279 this.DisposeOneConnection(streamHashCode ,key.Validation.cause) ; 源代码网推荐 280 } 源代码网推荐 281 } 源代码网推荐 282 源代码网推荐 283 key.StreamState = NetStreamState.Writing ; 源代码网推荐 284 if(repondList!= null && (repondList.Count != 0)) 源代码网推荐 285 { 源代码网推荐 286 foreach(object obj in repondList) 源代码网推荐 287 { 源代码网推荐 288 byte[] respond_stream = (byte[])obj ; 源代码网推荐 289 key.NetStream.Write(respond_stream ,0 ,respond_stream.Length) ; 源代码网推荐 290 if(this.ServiceCommitted != null) 源代码网推荐 291 { 源代码网推荐 292 RespondInformation info = new RespondInformation() ; 源代码网推荐 293 info.ConnectID = streamHashCode ; 源代码网推荐 294 info.ServiceKey = this.messageDispatcher.GetServiceKey(respond_stream) ; 源代码网推荐 295 info.repondData = respond_stream ; 源代码网推荐 296 this.ServiceCommitted(info) ; 源代码网推荐 297 } 源代码网推荐 298 源代码网推荐 299 this.ActivateUserActionEvent(streamHashCode ,TcpUserAction.FunctionAccess) ; 源代码网推荐 300 } 源代码网推荐 301 } 源代码网推荐 302 源代码网推荐 303 if(key.IsFirstMsg) 源代码网推荐 304 { 源代码网推荐 305 if(repondList == null || (repondList.Count == 0)) //表示第一条消息还未接收完全 源代码网推荐 306 { 源代码网推荐 307 key.IsFirstMsg = true ; 源代码网推荐 308 } 源代码网推荐 309 else 源代码网推荐 310 { 源代码网推荐 311 key.IsFirstMsg = false ; 源代码网推荐 312 } 源代码网推荐 313 } 源代码网推荐 314 源代码网推荐 315 key.StreamState = NetStreamState.Idle ; 源代码网推荐 316 源代码网推荐 317 key.ResetBuffer(leftData) ; 源代码网推荐 318 源代码网推荐 319 if(! this.stateIsStop) 源代码网推荐 320 { 源代码网推荐 321 //继续接收请求 源代码网推荐 322 this.RecieveDataFrom(key) ; 源代码网推荐 323 } 源代码网推荐 324 else //停止服务 源代码网推荐 325 { 源代码网推荐 326 this.DisposeOneConnection(streamHashCode ,DisconnectedCause.ServerStopped) ; 源代码网推荐 327 } 源代码网推荐 328 } 源代码网推荐 329 catch(Exception ee) 源代码网推荐 330 { 源代码网推荐 331 if(ee is System.IO.IOException) //正在读写流的时候,连接断开 源代码网推荐 332 { 源代码网推荐 333 this.DisposeOneConnection(streamHashCode ,DisconnectedCause.ServerStopped) ; 源代码网推荐 334 } 源代码网推荐 335 源代码网推荐 336 ee = ee ; 源代码网推荐 337 } 源代码网推荐 338 } 源代码网推荐 339 #endregion 源代码网推荐 340 源代码网推荐 341 CheckData#region CheckData 源代码网推荐 342 private bool CheckData(ContextKey key) 源代码网推荐 343 { 源代码网推荐 344 int streamHashcode = key.NetStream.GetHashCode() ; 源代码网推荐 345 if(this.stateIsStop) 源代码网推荐 346 { 源代码网推荐 347 this.DisposeOneConnection(streamHashcode ,DisconnectedCause.ServerStopped) ; 源代码网推荐 348 return false; 源代码网推荐 349 } 源代码网推荐 350 源代码网推荐 351 if(key.BytesRead == 0) //表示客户端掉线或非正常关闭连接 源代码网推荐 352 { 源代码网推荐 353 this.DisposeOneConnection(streamHashcode ,DisconnectedCause.LineOff) ; 源代码网推荐 354 return false ; 源代码网推荐 355 } 源代码网推荐 356 源代码网推荐 357 if(key.BytesRead == 8)//表示客户端正常关闭连接 源代码网推荐 358 { 源代码网推荐 359 string ss = System.Text.Encoding.BigEndianUnicode.GetString(key.Buffer ,0 ,8) ; 源代码网推荐 360 this.DisposeOneConnection(streamHashcode ,DisconnectedCause.LineOff) ; 源代码网推荐 361 return false; 源代码网推荐 362 } 源代码网推荐 363 源代码网推荐 364 return true ; 源代码网推荐 365 } 源代码网推荐 366 #endregion 源代码网推荐 367 #endregion 源代码网推荐 368 源代码网推荐 369 INet 成员#region INet 成员 源代码网推荐 370 源代码网推荐 371 public IReqestStreamDispatcher Dispatcher 源代码网推荐 372 { 源代码网推荐 373 set 源代码网推荐 374 { 源代码网推荐 375 this.messageDispatcher = (ITcpReqStreamDispatcher)value ; 源代码网推荐 376 } 源代码网推荐 377 } 源代码网推荐 378 源代码网推荐 379 public int Port 源代码网推荐 380 { 源代码网推荐 381 set 源代码网推荐 382 { 源代码网推荐 383 this.curPort = value ; 源代码网推荐 384 } 源代码网推荐 385 get 源代码网推荐 386 { 源代码网推荐 387 return this.curPort ; 源代码网推荐 388 } 源代码网推荐 389 } 源代码网推荐 390 源代码网推荐 391 public bool UserValidated 源代码网推荐 392 { 源代码网推荐 393 set 源代码网推荐 394 { 源代码网推荐 395 this.validateRequest = value ; 源代码网推荐 396 } 源代码网推荐 397 } 源代码网推荐 398 源代码网推荐 399 #endregion 源代码网推荐 400 } 源代码网推荐 源代码网推荐 今天介绍了Tcp通信层中的核心――Tcp组件,仅仅复用Tcp组件已经能为我们省去很多麻烦了,如果想进行更高层次的复用――整个Tcp通信层的复用,请关注本篇的续文。 源代码网推荐 源代码网推荐 源代码网推荐 做人要厚道,请注明转自酷网动力(www.ASPCOOL.COM)。 源代码网推荐 源代码网供稿. |
