最近在写一个IM聊天工具,从中遇到很多问题,也发现了很多好的文章,现将一篇介绍TCP通信层实现的文件介绍给大家,希望能帮助有这方面需求的朋友! 如下:(原文blog:http://zhuweisky.cnblogs.com/archive/2006/01/04/310814.html)
2006年已经来临,回首刚走过的2005,心中感慨万千。在人生和生活的目标上,有了清晰明确的定位,终于知道了自己喜欢什么样的生活,喜欢什么样的生活方式;在技术上,成熟了不少,眼界也开阔的不少,从面向对象到组件、从.Net到J2EE、从微软到开源,颇有收获。特别值得一提的是,认识了Rod Johnson这个大牛人,也终于在自己的项目中正式使用Spring.net框架来开发了,这确实是一个优秀的框架。而在已经到来的2006年,我有一个主要目标就是B/S应用开发,来填补自己在企业级开发上的另一半空白。
以前就很想将自己在Tcp通信层的开发心得、经验共享出来,但一直没有实现,究其原因,还是自己太懒了。今天终于找到一个时机,写下这篇文章,也算是对2005年的另一种形式的回忆吧。
绝大多数C/S(包括多层)结构的系统中,终端与服务器的通信都是通过Tcp进行的(使用Udp的也有一些,但是其相对于Tcp简单许多,所以不在这里的讨论之列)。通常,这样的C/S系统都需要处理极大的并发,也就是说随时都可能有成千上万个用户在线,并且每分钟都可能有数以百计的用户上线/下线。由于每个用户都与服务器存在着一个Tcp连接,如何管理所有这些连接,并使我们的Tcp通信层稳定高效地工作,是我开发的这个“TcpTcp通信层”设计实现的主要目标。
自从2004年9月开始至今,我就一直负责某C/S系统的服务器端的架构设计,并负责整个通信层的实现,在探索的过程中,逐渐形成了一套可复用的“Tcp通信层框架”(“框架”这个词真的蛮吓人,呵呵),其位于EnterpriseServerBase类库的EnterpriseServerBase.Network命名空间中。现将我在通信层这一块的设计/开发经验记录于此,以便日后回顾。也期大家多多赐教。
我期望的“Tcp通信层”并不只是能接受连接、管理连接、转发用户请求这么简单,为了构建一个高度可复用的、灵活的、可接插的Tcp通信层,需要定义很多的规则、接口、契约,这需要做很多的工作。“Tcp通信层”决不仅仅只是Tcp协议通信,由于通信与消息联系紧密,不可避免的需要将“通信的消息”纳入到我们的分析中来,比如,基于Tcp传输的特性,我们可能需要对接收到的消息进行分裂、重组等(后文中会解释为什么、以及如何做)。请允许我在这里澄清一下,如果只是解决“仅仅”的Tcp通信问题,我只需要介绍Tcp组件就可以了,但是如果要解决“整个Tcp通信层”的问题,并使之可高度复用,那就需要介绍很多额外的东西,比如,上面提到的“消息”,以及“消息”所涉及的通信协议。
在我们应用的通信层中,存在以Tcp组件为核心的多个组件,这些组件相互协作,以构建/实现高度可复用的Tcp通信层。这些组件之间的关系简单图示如下:
![](http://zhuweisky.cnblogs.com/images/cnblogs_com/zhuweisky/tcp.jpg)
我先解释一下上图。当网络(Tcp)组件从某个Tcp连接上接收到一个请求时,会将请求转发给消息分派器,消息分派器通过IDataStreamHelper组件获取请求消息的类型,然后根据此类型要求处理器工厂创建对应类型的请求处理器,请求处理器处理请求并返回结果。接下来再由网络组件把结果返回给终端用户。在消息分派器进行请求消息分派之前,可能涉及一系列的操作,像消息加密/解密、消息分裂/重组、消息验证等。而且,根据不同的应用,可能有其它的消息转换要求,而且这些操作可能是多样化的,为了满足这种多样性和可接插性,这就需要消息分派器提供一个插入点,让我们可以随心所欲地插入自定义的对请求/回复消息的预处理和后处理。
上图中消息分派器中可接插的操作除了消息分裂器(使用实线框)是必须的,消息加密器和消息验证器(使用虚线框)是可选的,应根据你应用的实际情况加以决定是否使用。关于这几个典型的可接插的组件的功能作用会在后文中介绍。在继续介绍Tcp组件的实现之前,有必要先提一下IDataStreamHelper接口的作用,IDataStreamHelper接口用于抽象我们实际的通信协议,并能从任何一请求/回复消息中提取关于本条消息的元数据,比如,消息的长度、类型等信息。具体的应用必须根据自己的消息协议来实现IDataStreamHelper接口。关于该接口的定义也在后文中给出。
关于上图,需要提醒的是,整个消息的流动是由Tcp组件驱动的!这篇文章以Tcp组件和消息分派器组件为索引来组织整个可复用的Tcp通信层的实现。首先,我们来深入到Tcp组件的具体实现中去。
一.Tcp组件
1.Tcp组件的主要职责
Tcp组件的主要职责并不是在一个很短的时间内总结出来的,它是逐步完善的(至今可能还不够全面)。为了使Tcp组件具有高度的可复用性,需要考虑很多的需求,而所有这些需求中具有共性的、占主导位置的需求就被纳入到Tcp组件的职责中来了。这个职责的集合如下:
(1) 管理所有的Tcp连接以及连接对应的上下文(Context)。
(2) 当某用户上线或下线时,能发出事件通知。
(3) 当在线用户(连接)的数量发生变化时,能发出事件通知。
(4) 当用户的请求得到回复时,发出事件通知。这一点对于记录用户请求和跟踪用户请求非常有用)
(5) 能及时主动关闭指定连接。比如,当某一非法用户登录后,用户验证组件通知Tcp组件强行关闭该用户对应的连接。
(6) 除了能转发用户请求及对请求的应答(通过消息分派器)外,还能直接对指定的用户发送数据。这也要求我们的Tcp连接是多线程安全的。
(7) 提供绕开Tcp组件直接从Tcp连接同步接收数据的功能。比如,客户端需要上传一个Blob,我们可能希望直接从Tcp连接进行接收数据,这是有好处的,后面可以看到。
这里列出的是Tcp组件的主要职责,还有很多细节性的没有罗列出来,如果一个Tcp组件解决了上述所有问题,对我来说,应该就是一个很好用、很适用的Tcp组件了。
2.Tcp组件接口定义
相信很多朋友和我一样,刚接触Tcp服务端开发的时候,通常是当一个Tcp连接建立的时候,就分配一个线程在该连接上监听请求消息,这种方式的缺点有很多,最主要的缺点是效率低、管理复杂。
我的最初的Tcp组件是C++版本的,那时很有幸接触到了windows平台上最高效的Tcp通信模型――完成端口模型,完全理解这个模型需要点时间,但是《Win32 多线程程序设计》(侯捷翻译)和《windows网络编程》这两本书可以给你不少帮助。异步机制是完成端口的基础,完成端口模型的本质思想是将"启动异步操作的线程"和"提供服务的线程"(即工作者线程)拆伙。理解这一点很重要。在.Net中没有对应的组件或类对应于完成端口模型,解决方案有两个:一是通过P/Invoke来实现自己的完成端口组件,另一种方式是通过.Net的现有通信设施来模拟完成端口实现。
本文给出第二种方案的实现说明,另外,我也给出通过“异步+线程池”的方式的Tcp组件实现,这种方式对于大并发量也可以很好的管理。也就是我,我的EnterpriseServerBase类库中,有两种不同方式的Tcp组件实现,一个是模拟完成端口模型,一个是“异步+线程池”方式。无论是哪种方式,它们都实现了相同的接口ITcp。ITcp这个接口涵盖了上述的Tcp组件的所有职责,这个接口并不复杂,如果理解了,使用起来也非常简单。我们来看看这个接口的定义:
public
interface
ITcp :INet ,ITcpEventList ,ITcpClientsController
{
int
ConnectionCount{
get
;}
//
当前连接的数量
}
这个接口继承了另外三个接口,INet ,ITcpEventList ,ITcpClientsController。INet接口是为了统一基于Tcp和Udp的通信组件而抽象出来的,它包含了以下内容: IReqestStreamDispatcher就是我们上述图中的消息分派器,这是Tcp通信层中的中央,它的重要性已从前面的关系图中可见一斑了。IReqestStreamDispatcher需要在初始化的时候提供,或者通过Dispatcher属性通过IOC容器进行设值法注入。UserValidated属性用于决定当用户的第一个请求不是登录请求时,是否立即关闭Tcp连接。其它的属性已经加上了注释,非常容易理解。
ITcpEventList接口说明了Tcp组件应当发布的事件,主要对应于前述Tcp组件职责的(2)(3)(4)点。其定义如下:
每一个在线用户都对应着一个Tcp连接,我们使用tcp连接的Hashcode作为ConnectID来标志每一个连接。UserAction将用户与服务器的交互分为三类:登录、退出和标准功能访问,如以下枚举所示。 这个接口中的方法的含义是一目了然的。
上述的几个接口已经完整的覆盖了前述的Tcp组件的所有职责,在了解了这些接口定义的基础上,大家已经能够使用EnterpriseServerBase类库中的Tcp组件了。如果想复用的不仅仅是Tcp组件,而是整个Tcp通信层,你就需要关注后面的内容。不管怎样,为了文章的完整性,我在这里先给出前面提到的Tcp组件的两种实现。
///
<summary>
///
ISafeNetworkStream 线程安全的网络流 。
///
注意:如果调用的异步的begin方法,就一定要调用对应的End方法,否则锁将得不到释放。
///
作者:朱伟 sky.zhuwei@163.com
///
</summary>
public interface ISafeNetworkStream :ITcpSender ,ITcpReciever
{
void Flush();
void Close() ;
}
//
用于在TCP连接上发送数据,支持同步和异步
public
interface
ITcpSender
{
void
Write(
byte
[] buffer ,
int
offset ,
int
size) ;
IAsyncResult BeginWrite(
byte
[] buffer,
int
offset,
int
size, AsyncCallback callback,
object
state );
void
EndWrite(IAsyncResult asyncResult );
}
//
用于在TCP连接上接收数据,支持同步和异步
public
interface
ITcpReciever
{
int
Read (
byte
[] buffer ,
int
offset ,
int
size) ;
IAsyncResult BeginRead(
byte
[] buffer,
int
offset,
int
size, AsyncCallback callback,
object
state );
int
EndRead(IAsyncResult asyncResult );
}
该接口几乎与System.Net.Sockets.NetworkStream提供的方法一样,只不过它们是线程安全的。这样,针对同一个SafeNetworkStream,我们就可以在不同的线程中同时在其上进行数据接收/发送(主要是发送)了。
(2)Tcp监听器EnterpriseServerBase.Network.XTcpListener
不可否认,System.Net.Sockets.TcpListener只是提供了一些最低阶的工作,为了将监听线程、端口、监听事件整合起来,我引入了EnterpriseServerBase.Network.XTcpListener类,它可以启动和停止,并且当有Tcp连接建立的时候,会触发事件。XTcpListener实现了IXTcpListener接口,其定义如下:
public
interface
IXTcpListener
{
void
Start() ;
//
开始或启动监听线程
void
Stop() ;
//
暂停,但不退出监听线程
void
ExitListenThread() ;
//
退出监听线程
event
CBackUserLogon TcpConnectionEstablished ;
//
新的Tcp连接成功建立
event
CallBackDynamicMsg DynamicMsgArrived ;
}
XTcpListener可以在不同的Tcp组件中复用,这是一种更细粒度的复用。
(3)用户连接上下文ContextKey
ContextKey用于将所有的与一个用户Tcp连接相关的信息(比如接收缓冲区、连接的状态――空闲还是忙碌、等)封装起来,并且还能保存该用户的请求中上次未处理完的数据,将其放于接收缓冲区的头部,并与后面接收到的数据进行重组。说到这里,你可能不太明白,我需要解释一下。Tcp协议可以保证我们发出的消息完整的、有序的、正确的到达目的地,但是它不能保证,我们一次发送的数据对方也能一次接收完全。比如,我们发送了一个100Bytes的数据,对方可能要接收两次才能完全,先收到60Bytes,再收到40Bytes,这表明我们可能会收到“半条”消息。还有一种情况,你连续发了两条100Bytes的消息,而对方可能一次就接收了160Bytes,所以需要对消息进行分裂,从中分裂出完整的消息然后进行处理。这,就是前面所说的需要对消息进行分裂、重组的原因。知道这点后,IContextKey接口应该比较容易理解了,因为该接口的很多元素的存在都是为了辅助解决这个问题。IContextKey的定义如下:
public
interface
IContextKey
{
NetStreamState StreamState{
get
;
set
;}
//
网络流的当前状态--空闲、忙碌
ISafeNetworkStream NetStream{
get
;
set
;}
byte
[] Buffer{
get
;
set
;}
//
接收缓冲区
int
BytesRead{
get
;
set
;}
//
本次接收的字节数
int
PreLeftDataLen{
get
;
set
;}
bool
IsFirstMsg{
get
;
set
;}
//
是否为建立连接后的第一条消息
int
StartOffsetForRecieve{
get
;}
int
MaxRecieveCapacity{
get
;}
//
本次可以接收的最大字节数
RequestData RequestData{
get
;}
void
ResetBuffer(
byte
[] leftData) ;
//
leftData 表示上次没有处理完的数据,需要与后面来的数据进行重组,然后再次处理
}
对于消息的分裂和重组是由消息分裂器完成的,由于Tcp组件的实现不需要使用消息分裂器,所以消息分裂器的说明将在后面的消息分派器实现中讲解。
(4)上下文管理者ContextKeyManager
ContextKeyManager用于管理所有的ContextKey,其实现的接口IContextKeyManager很容易理解:
public
interface
IContextKeyManager
{
void
InsertContextKey(ContextKey context_key) ;
void
DisposeAllContextKey() ;
bool
IsAllStreamSafeToStop() ;
//
是否可以安全退出
void
RemoveContextKey(
int
streamHashCode) ;
int
ConnectionCount {
get
;}
ISafeNetworkStream GetNetStream(
int
streamHashCode) ;
event
CallBackCountChanged StreamCountChanged ;
}
在上述四个基本元素的支持下,再来实现Tcp组件就方便了许多,无论是以何种方式(如完成端口模型、异步方式)实现Tcp组件,这些基本元素都是可以通用的,所以如果你要实现自己的Tcp组件,也可以考虑复用上述的一些基本元素。复用可以在不同的粒度进行,复用真是无处不在,呵呵。
4.完成端口Tcp组件实现
前面已经提到,完成端口模型本质思想是将"启动异步操作的线程"和"提供服务的线程"(即工作者线程)拆伙。只要做到这一点,就模拟了完成端口。
分析一下我们需要几种类型的线程,首先我们需要一个线程来接收TCP连接请求,这就是所谓监听线程,当成功的接收到一个连接后,就向连接发送一个异步接收数据的请求,由于是异步操作,所以会立即返回,然后再去接收新的连接请求,如此监听线程就循环运作起来了(已经封装成前述的XTcpListener组件了)。值得提出的是,在异步接收的回调函数中,应该对接收到的数据进行处理,完成端口模型所做的就是将接收到的数据放在了完成端口队列中,注意,是一个队列。第二种线程类型,就是工作者线程。工作者线程的个数有个经验值是( Cpu个数×2 + 2),当然具体取多少,还要取决于你的应用的要求。工作者线程的任务就是不断地从完成端口队列中取出数据,并处理它,然后如果有回复,再将回复写入对应的连接。
好,让我们来定义接口IRequestQueueManager,用于模拟完成端口的队列,该队列是线程安全的,用于将所有的请求进行排队,然后由工作者线程来轮流处理这些请求。
public
interface
IRequestQueueManager :IRequestPusher
{
object
Pop() ;
//
弹出队列中的下一个请求
void
Clear() ;
int
Length {
get
;}
//
队列长度
}
public
interface
IRequestPusher
{
void
Push(
object
package) ;
//
向队列中压入一个请求
}
在IRequestQueueManager的基础上,可以将工作者线程和启动异步操作的线程拆开了。由于工作者线程只与端口队列相关,所以我决定将它们一起封装起来--成为IIOCPManager,用于管理请求队列和工作者线程。
///
<summary>
///
IIOCPManager 完成端口管理者,主要管理工作者线程和完成端口队列。
///
</summary>
public
interface
IIOCPManager : IRequestPusher
{
void
Initialize(IOCPPackageHandler i_packageHandler ,
int
threadCount) ;
void
Start() ;
//
启动工作者线程
void
Stop() ;
//
退出工作者线程
int
WorkThreadCount{
get
;}
event
CallBackPackageHandled PackageHandled ;
}
//
IOCPPackageHandler 用于处理从完成端口队列中取出的package
public
interface
IOCPPackageHandler
{
void
HandlerPackage(
object
package) ;
//
一般以同步实现
}
有了IRequestQueueManager和IIOCPManager的支持,实现基于完成端口模型的Tcp组件就非常简单了。当然,你也可以单独使用IIOCPManager。你只要提供一个监听者线程接收连接,并将从连接接收到的数据通过IRequestPusher接口放入端口队列就可以了。 当然,为了处理接收到的数据,我们需要提供一个实现了IOCPPackageHandler接口的对象给IOCPManager。值得提出的是,你可以在数据处理并发送了回复数据后,再次投递一个异步接收请求,以保证能源源不断的从对应的TCP连接接收数据。下面,我们来看基于完成端口模型的Tcp组件的完整实现。
.异步Tcp组件实现
这种方式的主要思想是:当一个新的Tcp连接建立时,就在该连接上发送一个异步接收的请求(BeginRead),并在异步回调中处理该请求,当请求处理完毕,再次发送异步接收请求,如此循环下去。异步接收启用的是系统默认线程池中的线程,所以,在异步Tcp组件中不用显式管理工作线程。异步Tcp组件的实现相对于完成端口模型而言简单许多,也单纯一些,不用管理请求队列,不需使用工作者线程等等。但是,相比于完成端口模型,其也有明显的缺陷:一个Tcp连接绑定到了一个线程,即使这个线程是后台线程池中的。如果用户数量巨大,这对性能是极其不利的;而完成端口模型,则可以限定工作者线程的个数,并且可以根据应用的类型进行灵活调节。
异步Tcp组件实现源码。
完成端口Tcp组件
1![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//// <summary>
2
/// IocpTcp 完成端口Tcp组件。
3
/// </summary>
4
public class IocpTcp :ITcp ,IOCPPackageHandler
5![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
6![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
members#region members
7
private const int BufferSize = 1024 ;
8
private const int MaxWorkThreadNum = 50 ;
9![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
10
private IXTcpListener xtcpListener ;
11
private IIOCPManager iocpMgr = null ;
12
private ITcpReqStreamDispatcher messageDispatcher = null ;
13
private ContextKeyManager contextKeyMgr = new ContextKeyManager() ;
14
private bool stateIsStop = true ;
15
private bool validateRequest = false ;
16
private int curPort = 8888 ;
17
#endregion
18![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
19
public IocpTcp()
20![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
21
22
}
23![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
ITcp 成员#region ITcp 成员
24
public int ConnectionCount
25![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
26
get
27![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
28
return this.contextKeyMgr.ConnectionCount ;
29
}
30
}
31![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
32
#endregion
33![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
34![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
INet 成员#region INet 成员
35![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
36![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
InitializeAll ,UnitializeAll#region InitializeAll ,UnitializeAll
37
public void InitializeAll(IReqestStreamDispatcher i_dispatcher ,int port , bool userValidated)
38![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
39
this.messageDispatcher = i_dispatcher as ITcpReqStreamDispatcher;
40
if(this.messageDispatcher == null)
41![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
42
throw new Exception("Can't convert IReqestStreamDispatcher to ITcpReqStreamDispatcher in CompletePortManager.InitializeAll method ! ") ;
43
}
44![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
45
this.validateRequest = userValidated ;
46
this.curPort = port ;
47![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
48
this.InitializeAll() ;
49
}
50![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
51
public void InitializeAll()
52![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
53
this.xtcpListener = new XTcpListener(this.curPort) ;
54
this.xtcpListener.TcpConnectionEstablished += new CBackUserLogon(xtcpListener_TcpConnectionEstablished);
55
this.xtcpListener.DynamicMsgArrived += new CallBackDynamicMsg(this.PutoutDynamicMsg) ;
56
this.contextKeyMgr.StreamCountChanged += new CallBackCountChanged (this.OnStreamCountChanged) ;
57
58
this.iocpMgr = new IOCPManager() ;
59
this.iocpMgr.Initialize(this , IocpTcp.MaxWorkThreadNum) ;
60
}
61![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
62
public void UnitializeAll()
63![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
64
this.Stop() ;
65
this.xtcpListener.ExitListenThread() ;
66![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
67
//将事件容器清空==》防止外部框架再多次初始化的过程中将一个事件预定多次
68
this.ConnectionCountChanged = null ;
69
this.DynamicMsgArrived = null ;
70
this.ServiceCommitted = null ;
71
this.SomeOneConnected = null ;
72
this.SomeOneDisConnected = null ;
73
this.UserAction = null ;
74
}
75
#endregion
76![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
77![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Start ,Stop#region Start ,Stop
78
public void Start()
79![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
80
try
81![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
82
if(this.stateIsStop)
83![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
84
this.stateIsStop = false ;
85
this.xtcpListener.Start() ;
86
this.iocpMgr.Start() ;
87
}
88
}
89
catch(Exception ee)
90![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
91
throw ee ;
92
}
93
}
94![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
95
public void Stop()
96![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
97
if(this.stateIsStop)
98![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
99
return ;
100
}
101![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
102
this.stateIsStop = true ;
103
this.xtcpListener.Stop() ;
104
this.iocpMgr.Stop() ;
105![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
106
//关闭所有连接
107
int count = 0 ;
108
while(! this.contextKeyMgr.IsAllStreamSafeToStop()) //等待所有流到达停止安全点
109![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
110
Thread.Sleep(200) ;
111
if(10 == count++)
112![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
113
break ;
114
}
115
}
116
this.contextKeyMgr.DisposeAllContextKey() ;
117
}
118
#endregion
119![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
120
public event EnterpriseServerBase.Network.CallBackDynamicMessage DynamicMsgArrived;
121![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
122
public NetAddinType GetProtocalType()
123![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
124
return NetAddinType.Tcp ;
125
}
126![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
127
#endregion
128![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
129![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
ITcpEventList 成员#region ITcpEventList 成员
130
public event EnterpriseServerBase.Network.CallBackForTcpUser2 SomeOneConnected;
131![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
132
public event EnterpriseServerBase.Network.CallBackForTcpMonitor ServiceCommitted;
133![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
134
public event EnterpriseServerBase.Network.CallBackForTcpCount ConnectionCountChanged;
135![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
136
public event EnterpriseServerBase.Network.CallBackForTcpUser1 SomeOneDisConnected;
137![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
138
public event EnterpriseServerBase.Network.CallBackForTcpUser UserAction;
139![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
140
#endregion
141![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
142![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
ITcpClientsController 成员#region ITcpClientsController 成员
143![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
144
public void SendData(int ConnectID, byte[] data)
145![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
146
this.SendData(ConnectID ,data ,0 ,data.Length) ;
147
}
148![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
149
public void SendData(int ConnectID, byte[] data ,int offset ,int size)
150![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
151
if((data == null) || (data.Length == 0) || (offset <0) ||(size <0) || (offset+size > data.Length))
152![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
153
return ;
154
}
155![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
156
ISafeNetworkStream netStream = this.contextKeyMgr.GetNetStream(ConnectID) ;
157
if(netStream == null)
158![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
159
return ;
160
}
161![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
162
netStream.Write(data ,offset ,size) ;
163
}
164![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
165
public bool SynRecieveFrom(int ConnectID ,byte[] buffer, int offset, int size ,out int readCount)
166![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
167
readCount = 0 ;
168
ISafeNetworkStream netStream = this.contextKeyMgr.GetNetStream(ConnectID) ;
169
if(netStream == null)
170![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
171
return false ;
172
}
173![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
174
readCount = netStream.Read(buffer ,offset ,size) ;
175![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
176
return true ;
177
}
178![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
179
public void DisposeOneConnection(int connectID, EnterpriseServerBase.Network.DisconnectedCause cause)
180![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
181
this.DisposeOneConnection(connectID) ;
182![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
183
if(this.SomeOneDisConnected != null)
184![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
185
this.SomeOneDisConnected(connectID ,cause) ;
186
}
187![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
188
this.ActivateUserActionEvent(connectID ,TcpUserAction.Exit) ;
189
}
190![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
191![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
192
/// DisposeOneConnection 主要由用户管理模块调用--当无法检测到掉线情况时,该方法保证资源被释放
193
/// </summary>
194
private void DisposeOneConnection(int connectID)
195![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
196
this.contextKeyMgr.RemoveContextKey(connectID) ;
197
}
198![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
199
#endregion
200![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
201![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
private#region private
202![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
BindRequestToQueue#region BindRequestToQueue
203
private void BindRequestToQueue(IAsyncResult ar)
204![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
205
try
206![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
207
ContextKey key = (ContextKey)ar.AsyncState ;
208
key.BytesRead = key.NetStream.EndRead(ar) ;
209
if(! this.CheckData(key))
210![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
211
return ;
212
}
213![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
214
this.iocpMgr.Push(key) ;
215
}
216
catch(Exception ee)
217![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
218
ee = ee ;
219
}
220
}
221![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
222![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
CheckData#region CheckData
223
private bool CheckData(ContextKey key)
224![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
225
int streamHashcode = key.NetStream.GetHashCode() ;
226
if(this.stateIsStop)
227![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
228
this.DisposeOneConnection(streamHashcode ,DisconnectedCause.ServerStopped) ;
229
return false;
230
}
231![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
232
if(key.BytesRead == 0) //表示客户端掉线或非正常关闭连接
233![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
234
this.DisposeOneConnection(streamHashcode ,DisconnectedCause.LineOff) ;
235
return false ;
236
}
237![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
238
if(key.BytesRead == 8)//表示客户端正常关闭连接
239![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
240
string ss = System.Text.Encoding.BigEndianUnicode.GetString(key.Buffer ,0 ,8) ;
241
this.DisposeOneConnection(streamHashcode ,DisconnectedCause.LineOff) ;
242
return false;
243
}
244![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
245
return true ;
246
}
247
#endregion
248
#endregion
249![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
250![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
xtcpListener_TcpConnectionEstablished#region xtcpListener_TcpConnectionEstablished
251
private void xtcpListener_TcpConnectionEstablished(NetworkStream stream)
252![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
253
ISafeNetworkStream safeStream = new SafeNetworkStream(stream) ;
254
ContextKey key = new ContextKey(safeStream ,IocpTcp.BufferSize) ;
255
key.ResetBuffer(null) ;
256
this.contextKeyMgr.InsertContextKey(key) ;
257
int connectID = key.NetStream.GetHashCode() ;
258
if(this.SomeOneConnected != null)
259![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
260
this.SomeOneConnected(connectID) ;
261
}
262
263
this.ActivateUserActionEvent(connectID ,TcpUserAction.Logon) ;
264![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
265
key.IsFirstMsg = true ;
266
this.RecieveDataFrom(key) ;
267
}
268
#endregion
269![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
270![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
ActivateUserActionEvent#region ActivateUserActionEvent
271
private void ActivateUserActionEvent(int ConnectID ,TcpUserAction action)
272![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
273
if(this.UserAction != null)
274![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
275
this.UserAction(ConnectID ,action) ;
276
}
277
}
278
#endregion
279![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
280![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
PutoutDynamicMsg#region PutoutDynamicMsg
281
private void PutoutDynamicMsg(string msg)
282![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
283
if(this.DynamicMsgArrived != null)
284![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
285
this.DynamicMsgArrived(msg) ;
286
}
287
}
288
#endregion
289![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
290![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
OnStreamCountChanged#region OnStreamCountChanged
291
private void OnStreamCountChanged(int count)
292![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
293
if(this.ConnectionCountChanged != null)
294![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
295
this.ConnectionCountChanged(count) ;
296
}
297
}
298
#endregion
299![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
300![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
RecieveDataFrom#region RecieveDataFrom
301
private void RecieveDataFrom(ContextKey key)
302![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
303
try
304![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
305
key.StreamState = NetStreamState.Reading ;
306
key.NetStream.BeginRead(key.Buffer ,key.StartOffsetForRecieve ,key.MaxRecieveCapacity ,new AsyncCallback(this.BindRequestToQueue) ,key) ;
307
}
308
catch(Exception ee)
309![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
310
ee = ee ;
311
}
312
313
}
314
#endregion
315
#endregion
316![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
317![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
IOCPPackageHandler 成员#region IOCPPackageHandler 成员
318![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
319
public void HandlerPackage(object package)
320![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
321
ContextKey key = package as ContextKey ;
322
if(key == null)
323![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
324
return ;
325
}
326![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
327
int streamHashCode = key.NetStream.GetHashCode() ; //是SafeNetworkStream的hashcode
328![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
329
//处理请求
330
try
331![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
332
byte[] leftData = null ;
333
ArrayList repondList = this.messageDispatcher.DealRequestMessage(key.RequestData ,out leftData , ref key.Validation) ;
334
335
if(this.validateRequest)
336![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
337
if(key.Validation.gotoCloseConnection)
338![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
339
this.DisposeOneConnection(streamHashCode ,key.Validation.cause) ;
340
return ;
341
}
342
}
343![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
344
key.StreamState = NetStreamState.Writing ;
345
if(repondList!= null && (repondList.Count != 0))
346![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
347
foreach(object obj in repondList)
348![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
349
byte[] respond_stream = (byte[])obj ;
350
key.NetStream.Write(respond_stream ,0 ,respond_stream.Length) ;
351
if(this.ServiceCommitted != null)
352![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
353
RespondInformation info = new RespondInformation() ;
354
info.ConnectID = streamHashCode ;
355
info.ServiceKey = this.messageDispatcher.GetServiceKey(respond_stream) ;
356
info.repondData = respond_stream ;
357
this.ServiceCommitted(info) ;
358
}
359
this.ActivateUserActionEvent(streamHashCode ,TcpUserAction.FunctionAccess) ;
360
}
361
}
362![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
363
if(key.IsFirstMsg)
364![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
365
if(repondList == null || (repondList.Count == 0)) //表示第一条消息还未接收完全
366![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
367
key.IsFirstMsg = true ;
368
}
369
else
370![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
371
key.IsFirstMsg = false ;
372
}
373
}
374
375
key.StreamState = NetStreamState.Idle ;
376
377
key.ResetBuffer(leftData) ;
378![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
379
if(! this.stateIsStop)
380![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
381
//继续接收请求
382
this.RecieveDataFrom(key) ;
383
}
384
else //停止服务
385![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
386
this.DisposeOneConnection(streamHashCode ,DisconnectedCause.ServerStopped) ;
387
}
388
}
389
catch(Exception ee)
390![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
391
if(ee is System.IO.IOException) //正在读写流的时候,连接断开
392![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
393
this.DisposeOneConnection(streamHashCode ,DisconnectedCause.ServerStopped) ;
394
}
395![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
396
ee = ee ;
397
}
398
}
399![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
400
#endregion
401![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
402![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
INet 成员#region INet 成员
403![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
404
public IReqestStreamDispatcher Dispatcher
405![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
406
set
407![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
408
this.messageDispatcher = (ITcpReqStreamDispatcher)value ;
409
}
410
}
411![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
412
public int Port
413![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
414
set
415![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
416
this.curPort = value ;
417
}
418
get
419![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
420
return this.curPort ;
421
}
422
}
423![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
424
public bool UserValidated
425![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
426
set
427![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
428
this.validateRequest = value ;
429
}
430
}
431![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
432
#endregion
433
}
5
今天介绍了Tcp通信层中的核心――Tcp组件,仅仅复用Tcp组件已经能为我们省去很多麻烦了,如果想进行更高层次的复用――整个Tcp通信层的复用,请关注本篇的续文。
异步Tcp组件
1![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//// <summary>
2
/// AsynTcp 异步Tcp组件。
3
/// </summary>
4
public class AsynTcp :ITcp
5![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
6![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
members#region members
7
private const int BufferSize = 1024 ;
8![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
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![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
17![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
18
public AsynTcp()
19![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
20
21
}
22![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
23![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
INet 成员#region INet 成员
24![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
25
public event CallBackDynamicMessage DynamicMsgArrived;
26![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
27
public NetAddinType GetProtocalType()
28![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
29
30
return NetAddinType.Tcp;
31
}
32![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
33![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
InitializeAll ,UnitializeAll#region InitializeAll ,UnitializeAll
34
public void InitializeAll(IReqestStreamDispatcher i_dispatcher, int port, bool userValidated)
35![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
36
this.messageDispatcher = i_dispatcher as ITcpReqStreamDispatcher;
37
if(this.messageDispatcher == null)
38![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
39
throw new Exception("Can't convert IReqestStreamDispatcher to ITcpReqStreamDispatcher in CompletePortManager.InitializeAll method ! ") ;
40
}
41![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
42
this.curPort = port ;
43
this.validateRequest = userValidated ;
44![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
45
this.InitializeAll() ;
46
}
47![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
48
public void InitializeAll()
49![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
56
public void UnitializeAll()
57![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
58
this.Stop() ;
59
this.xtcpListener.ExitListenThread() ;
60![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
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![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
72![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Start ,Stop#region Start ,Stop
73
public void Start()
74![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
75
if(this.stateIsStop)
76![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
77
this.xtcpListener.Start() ;
78
this.stateIsStop = false ;
79
}
80
}
81![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
82
public void Stop()
83![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
84
if(this.stateIsStop)
85![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
86
return ;
87
}
88![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
89
this.stateIsStop = true ;
90
this.xtcpListener.Stop() ;
91![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
92
//关闭所有连接
93
int count = 0 ;
94
while(! this.contextKeyMgr.IsAllStreamSafeToStop()) //等待所有流到达停止安全点
95![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
96
Thread.Sleep(200) ;
97
if(10 == count++)
98![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
99
break ;
100
}
101
}
102
this.contextKeyMgr.DisposeAllContextKey() ;
103
}
104
#endregion
105![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
106
#endregion
107![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
108![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
ITcpEventList 成员#region ITcpEventList 成员
109![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
110
public event EnterpriseServerBase.Network.CallBackForTcpUser2 SomeOneConnected;
111![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
112
public event EnterpriseServerBase.Network.CallBackForTcpMonitor ServiceCommitted;
113![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
114
public event EnterpriseServerBase.Network.CallBackForTcpCount ConnectionCountChanged;
115![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
116
public event EnterpriseServerBase.Network.CallBackForTcpUser1 SomeOneDisConnected;
117![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
118
public event EnterpriseServerBase.Network.CallBackForTcpUser UserAction;
119![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
120
#endregion
121![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
122![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
ITcpClientsController 成员#region ITcpClientsController 成员
123![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
124
public bool SynRecieveFrom(int ConnectID ,byte[] buffer, int offset, int size ,out int readCount)
125![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
126
readCount = 0 ;
127
ISafeNetworkStream netStream = this.contextKeyMgr.GetNetStream(ConnectID) ;
128
if(netStream == null)
129![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
130
return false ;
131
}
132![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
133
readCount = netStream.Read(buffer ,offset ,size) ;
134![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
135
return true ;
136
}
137![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
138
public void SendData(int ConnectID, byte[] data)
139![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
140
this.SendData(ConnectID ,data ,0 ,data.Length) ;
141
}
142![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
143
public void SendData(int ConnectID, byte[] data ,int offset ,int size)
144![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
145
if((data == null) || (data.Length == 0) || (offset <0) ||(size <0) || (offset+size > data.Length))
146![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
147
return ;
148
}
149![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
150
ISafeNetworkStream netStream = this.contextKeyMgr.GetNetStream(ConnectID) ;
151
if(netStream == null)
152![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
153
return ;
154
}
155![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
156
netStream.Write(data ,offset ,size) ;
157
}
158![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
159
public void DisposeOneConnection(int connectID, DisconnectedCause cause)
160![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
161
this.DisposeOneConnection(connectID) ;
162![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
163
if(this.SomeOneDisConnected != null)
164![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
165
this.SomeOneDisConnected(connectID , cause) ;
166
}
167![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
168
this.ActivateUserActionEvent(connectID ,TcpUserAction.Exit) ;
169
}
170![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
171
#endregion
172![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
173![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
ITcp 成员#region ITcp 成员
174
public int ConnectionCount
175![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
176
get
177![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
178
return this.contextKeyMgr.ConnectionCount ;
179
}
180
}
181![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
182
#endregion
183![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
184![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
private#region private
185![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
186![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
ActivateUserActionEvent#region ActivateUserActionEvent
187
private void ActivateUserActionEvent(int ConnectID ,TcpUserAction action)
188![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
189
if(this.UserAction != null)
190![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
191
this.UserAction(ConnectID ,action) ;
192
}
193
}
194
#endregion
195![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
196![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
DisposeOneConnection#region DisposeOneConnection
197![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
198
/// DisposeOneConnection 主要由用户管理模块调用--当无法检测到掉线情况时,该方法保证资源被释放
199
/// </summary>
200
private void DisposeOneConnection(int connectID)
201![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
202
this.contextKeyMgr.RemoveContextKey(connectID) ;
203
}
204
#endregion
205![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
206![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
xtcpListener_TcpConnectionEstablished#region xtcpListener_TcpConnectionEstablished
207
private void xtcpListener_TcpConnectionEstablished(NetworkStream stream)
208![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
216
if(this.SomeOneConnected != null)
217![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
218
this.SomeOneConnected(connectID) ;
219
}
220
this.ActivateUserActionEvent(connectID ,TcpUserAction.Logon) ;
221![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
222
key.IsFirstMsg = true ;
223
this.RecieveDataFrom(key) ;
224
}
225
#endregion
226![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
227![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
PutoutDynamicMsg#region PutoutDynamicMsg
228
private void PutoutDynamicMsg(string msg)
229![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
230
if(this.DynamicMsgArrived != null)
231![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
232
this.DynamicMsgArrived(msg) ;
233
}
234
}
235
#endregion
236![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
237![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
OnStreamCountChanged#region OnStreamCountChanged
238
private void OnStreamCountChanged(int count)
239![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
240
if(this.ConnectionCountChanged != null)
241![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
242
this.ConnectionCountChanged(count) ;
243
}
244
}
245
#endregion
246![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
247![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
RecieveDataFrom#region RecieveDataFrom
248
private void RecieveDataFrom(ContextKey key)
249![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
256![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
ServeOverLap#region ServeOverLap
257
private void ServeOverLap(IAsyncResult ar)
258![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
259
ContextKey key = (ContextKey)ar.AsyncState ;
260
int streamHashCode = key.NetStream.GetHashCode() ; //是SafeNetworkStream的hashcode
261![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
262
try
263![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
264
key.BytesRead = key.NetStream.EndRead(ar) ;
265![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
266
if(! this.CheckData(key))
267![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
268
return ;
269
}
270![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
271
//处理请求
272
byte[] leftData = null ;
273
ArrayList repondList = this.messageDispatcher.DealRequestMessage(key.RequestData ,out leftData , ref key.Validation) ;
274
275
if(this.validateRequest)
276![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
277
if(key.Validation.gotoCloseConnection)
278![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
279
this.DisposeOneConnection(streamHashCode ,key.Validation.cause) ;
280
}
281
}
282![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
283
key.StreamState = NetStreamState.Writing ;
284
if(repondList!= null && (repondList.Count != 0))
285![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
286
foreach(object obj in repondList)
287![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
288
byte[] respond_stream = (byte[])obj ;
289
key.NetStream.Write(respond_stream ,0 ,respond_stream.Length) ;
290
if(this.ServiceCommitted != null)
291![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
299
this.ActivateUserActionEvent(streamHashCode ,TcpUserAction.FunctionAccess) ;
300
}
301
}
302![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
303
if(key.IsFirstMsg)
304![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
305
if(repondList == null || (repondList.Count == 0)) //表示第一条消息还未接收完全
306![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
307
key.IsFirstMsg = true ;
308
}
309
else
310![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
311
key.IsFirstMsg = false ;
312
}
313
}
314
315
key.StreamState = NetStreamState.Idle ;
316
317
key.ResetBuffer(leftData) ;
318![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
319
if(! this.stateIsStop)
320![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
321
//继续接收请求
322
this.RecieveDataFrom(key) ;
323
}
324
else //停止服务
325![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
326
this.DisposeOneConnection(streamHashCode ,DisconnectedCause.ServerStopped) ;
327
}
328
}
329
catch(Exception ee)
330![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
331
if(ee is System.IO.IOException) //正在读写流的时候,连接断开
332![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
333
this.DisposeOneConnection(streamHashCode ,DisconnectedCause.ServerStopped) ;
334
}
335![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
336
ee = ee ;
337
}
338
}
339
#endregion
340![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
341![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
CheckData#region CheckData
342
private bool CheckData(ContextKey key)
343![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
344
int streamHashcode = key.NetStream.GetHashCode() ;
345
if(this.stateIsStop)
346![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
347
this.DisposeOneConnection(streamHashcode ,DisconnectedCause.ServerStopped) ;
348
return false;
349
}
350![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
351
if(key.BytesRead == 0) //表示客户端掉线或非正常关闭连接
352![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
353
this.DisposeOneConnection(streamHashcode ,DisconnectedCause.LineOff) ;
354
return false ;
355
}
356![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
357
if(key.BytesRead == 8)//表示客户端正常关闭连接
358![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
359
string ss = System.Text.Encoding.BigEndianUnicode.GetString(key.Buffer ,0 ,8) ;
360
this.DisposeOneConnection(streamHashcode ,DisconnectedCause.LineOff) ;
361
return false;
362
}
363![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
364
return true ;
365
}
366
#endregion
367
#endregion
368![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
369![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
INet 成员#region INet 成员
370![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
371
public IReqestStreamDispatcher Dispatcher
372![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
373
set
374![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
375
this.messageDispatcher = (ITcpReqStreamDispatcher)value ;
376
}
377
}
378![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
379
public int Port
380![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
381
set
382![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
383
this.curPort = value ;
384
}
385
get
386![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
387
return this.curPort ;
388
}
389
}
390![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
391
public bool UserValidated
392![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
393
set
394![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
395
this.validateRequest = value ;
396
}
397
}
398![](http://zhuweisky.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
399
#endregion
400
}
public
enum
TcpUserAction
{
Logon , Exit , FunctionAccess ,
//
标准的功能访问
}
最后一个接口ITcpClientsController,主要用来完成上述Tcp组件职责的(5)(6)(7)三点。定义如下:
///
<summary>
///
ITcpController 用于服务器主动控制TCP客户的连接
///
</summary>
public
interface
ITcpClientsController
{
//
同步接收消息
bool
SynRecieveFrom(
int
ConnectID ,
byte
[] buffer,
int
offset,
int
size ,
out
int
readCount) ;
//
主动给某个客户同步发信息
void
SendData(
int
ConnectID ,
byte
[] data) ;
void
SendData(
int
ConnectID,
byte
[] data ,
int
offset ,
int
size) ;
//
主动关闭连接
void
DisposeOneConnection(
int
connectID ,DisconnectedCause cause) ;
}
3.Tcp组件基本元素实现
在实现Tcp组件之前,有一些基本元素需要先建立起来,比如安全的网络流、Tcp监听器、用户连接上下文、上下文管理者等。(1)安全的网络流SafeNetworkStream
前面已经提到过,为了能在Tcp组件外部 对指定的连接发送数据,必须保证我们的Tcp连接是线程安全的,而System.Net.Sockets.NetworkStream是非线程安全的,我们必须自己对其进行封装,以保证这一点。System.Net.Sockets.NetworkStream的线程安全的封装就是EnterpriseServerBase.Network.SafeNetworkStream类,它继承了ISafeNetworkStream接口:
public
interface
INet
{
void
InitializeAll(IReqestStreamDispatcher i_dispatcher ,
int
port ,
bool
userValidated) ;
void
InitializeAll() ;
void
UnitializeAll() ;
NetAddinType GetProtocalType() ;
//
Udp, Tcp
event
CallBackDynamicMessage DynamicMsgArrived ;
//
通常是通信插件中一些与服务和用户无关的动态信息,如监听线程重启等
void
Start() ;
void
Stop() ;
IReqestStreamDispatcher Dispatcher{
set
;}
//
支持依赖注入
int
Port{
get
;
set
;}
bool
UserValidated{
set
;}
}
public
enum
NetAddinType
{
Tcp ,Udp
}
public
delegate
void
CallBackDynamicMessage(
string
msg) ;
public
interface
ITcpEventList
{
event
CallBackForTcpUser2 SomeOneConnected ;
//
上线
event
CallBackForTcpUser1 SomeOneDisConnected ;
//
掉线
event
CallBackForTcpCount ConnectionCountChanged ;
//
在线人数变化
event
CallBackForTcpMonitor ServiceCommitted ;
//
用户请求的服务的回复信息
event
CallBackForTcpUser UserAction ;
}