TCP通信层实现.docx

上传人:b****5 文档编号:3025388 上传时间:2022-11-17 格式:DOCX 页数:27 大小:31.86KB
下载 相关 举报
TCP通信层实现.docx_第1页
第1页 / 共27页
TCP通信层实现.docx_第2页
第2页 / 共27页
TCP通信层实现.docx_第3页
第3页 / 共27页
TCP通信层实现.docx_第4页
第4页 / 共27页
TCP通信层实现.docx_第5页
第5页 / 共27页
点击查看更多>>
下载资源
资源描述

TCP通信层实现.docx

《TCP通信层实现.docx》由会员分享,可在线阅读,更多相关《TCP通信层实现.docx(27页珍藏版)》请在冰豆网上搜索。

TCP通信层实现.docx

TCP通信层实现

.NET下可复用的TCP通信层实现之TCP组件

2006年已经来临,回首刚走过的2005,心中感慨万千。

在人生和生活的目标上,有了清楚明确的定位,终于知道了自己喜欢什么样的生活,喜欢什么样的生活方式;在技术上,成熟了不少,眼界也开阔的不少,从面向对象到组件、从.Net到J2EE、从微软到开源,颇有收获。

非凡值得一提的是,熟悉了RodJohnson这个大牛人,也终于在自己的项目中正式使用S框架来开发了,这确实是一个优秀的框架。

而在已经到来的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通信层。

这些组件之间的关系简单图示如下:

软件开发网

  我先解释一下上图。

当网络(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组件的所有职责,这个接口并不复杂,假如理解了,使用起来也非常简单。

我们来看看这个接口的定义:

publicinterfaceITcp:

INet,ITcpEventList,ITcpClientsController

{

 intConnectionCount{get;}//当前连接的数量

}

  这个接口继续了另外三个接口,INet,ITcpEventList,ITcpClientsController。

INet接口是为了统一基于Tcp和Udp的通信组件而抽象出来的,它包含了以下内容:

publicinterfaceINet

{

 voidInitializeAll(IReqestStreamDispatcheri_dispatcher,intport,booluserValidated);

 voidInitializeAll();

 voidUnitializeAll();

 NetAddinTypeGetProtocalType();//Udp,Tcp

 eventCallBackDynamicMessageDynamicMsgArrived;

 //通常是通信插件中一些与服务和用户无关的动态信息,如监听线程重启等

 voidStart();

 voidStop();

 IReqestStreamDispatcherDispatcher{set;}//支持依靠注入

 intPort{get;set;}

 boolUserValidated{set;}

}

publicenumNetAddinType

{

 Tcp,Udp

}

publicdelegatevoidCallBackDynamicMessage(stringmsg);

  IReqestStreamDispatcher就是我们上述图中的消息分派器,这是Tcp通信层中的中心,它的重要性已从前面的关系图中可见一斑了。

IReqestStreamDispatcher需要在初始化的时候提供,或者通过Dispatcher属性通过IOC容器进行设值法注入。

UserValidated属性用于决定当用户的第一个请求不是登录请求时,是否立即关闭Tcp连接。

其它的属性已经加上了注释,非常轻易理解。

  ITcpEventList接口说明了Tcp组件应当发布的事件,主要对应于前述Tcp组件职责的

(2)(3)(4)点。

其定义如下:

publicinterfaceITcpEventList

{

 eventCallBackForTcpUser2SomeOneConnected;//上线

 eventCallBackForTcpUser1SomeOneDisConnected;//掉线

 eventCallBackForTcpCountConnectionCountChanged;//在线人数变化

 eventCallBackForTcpMonitorServiceCommitted;//用户请求的服务的回复信息

 eventCallBackForTcpUserUserAction;

}

  每一个在线用户都对应着一个Tcp连接,我们使用tcp连接的Hashcode作为ConnectID来标志每一个连接。

UserAction将用户与服务器的交互分为三类:

登录、退出和标准功能访问,如以下枚举所示。

publicenumTcpUserAction

{

 Logon,Exit,FunctionAccess,//标准的功能访问

}

  最后一个接口ITcpClientsController,主要用来完成上述Tcp组件职责的(5)(6)(7)三点。

定义如下:

///

///ITcpController用于服务器主动控制TCP客户的连接

///

publicinterfaceITcpClientsController

{

 //同步接收消息

 boolSynRecieveFrom(intConnectID,byte[]buffer,intoffset,int

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 教学研究 > 教学计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1