·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> 网站建设开发 >> ASP.NET网站开发 >> 基于 Asp.Net的 Comet 技术解析

基于 Asp.Net的 Comet 技术解析

作者:佚名      ASP.NET网站开发编辑:admin      更新时间:2022-07-23

基于 asp.net的 Comet 技术解析

Comet技术原理

来自维基百科:Comet是一种用于web的技术,能使服务器能实时地将更新的信息传送到客户端,而无须客户端发出请求,目前有两种实现方式,长轮询和iframe流。

简单的说是一种基于现有Http协议基础上的长轮询技术,之所有会产生这种技术的主要原因是Http协议是无状态的所以客户端和服务端之间没办法建立起一套长时间的连接。比如我们要做一个聊天室,在Web环境下我们通常不能从服务端推送消息到浏览器里,而只能通过每个客户端不断的轮询服务器,以获取最新的消息,这样一来效率非常低,而且不断的向服务器发送请求对于访问量大的应用来说也会造成很大的资源占用。

于是人们就发现了这种技术,向服务器发起一个请求,然后服务器一直不响应这个请求,这样客户端和服务端之间就形成了一个长连接,直到服务端响应这个请求后结束本次连接。借用一下IBM里的图片:

通过Ajax技术可以实现长轮询的服务器推模型,客户端和服务端之间通过不断的发起长轮询即可以实现数据的交互,这个过程由于是Ajax实现的异步操作所以体验上会比较好,效率也很高。哎呀呀,说不清楚,找个网上的资料:

Comet方式通俗的说就是一种长连接机制(longlivedhttp)。同样是由Browser端主动发起请求,但是Server端以一种似乎非常慢的响应方式给出回答。这样在这个期间内,服务器端可以使用同一个connection把要更新的数据主动发送给Browser。因此请求可能等待较长的时间,期间没有任何数据返回,但是一旦有了新的数据,它将立即被发送到客户机。Comet又有很多种实现方式,但是总的来说对Server端的负载都会有增加.虽然对于单位操作来说,每次只需要建议一次connection,但是由于connection是保持较长时间的,对于server端的资源的占用要有所增加。

优点:实时性好(消息延时小);性能好(能支持大量用户)

缺点:长期占用连接,丧失了无状态高并发的特点。

应用:股票系统、实时通讯。

参考资料:

Comet:基于HTTP长连接的“服务器推”技术

基于Asp.Net的实现Comet的技术基础

Asp.Net本身就是为web而生的技术,所以先天是满足滴。基于Ajax技术与Asp.net的异步请求处理可以为Comet提供更加强大的能力。在此隆重推出:IHttpAsyncHandler接口。

  • IHttpAsyncHandler接口简介

IhttpAsyncHandler是继承于IhttpHandler,但是不同的是IHttpAsyncHandler具有天生的异步能力。他比IHttpHandler多2个方法:

IAsyncResultBeginPRocessRequest(HttpContextcontext,AsyncCallbackcb,objectextraData);voidEndProcessRequest(IAsyncResultresult);

BeginProcessRequest方法返回的是IAsyncResult接口,通常在BeginProcessRequest中处理一些比较繁重费时的任务,比如IO操作,读取Web服务等。一旦异步操作完成之后,则可以通过EndProcessRequest方法获得异步的结果。

IHttpAsyncHandler的好处在于,在它处理异步方法的时候,处理请求的线程可以暂时得到释放,而有空闲去处理其他请求,等异步方法运行完毕之后,在由线程去处理接下来的请求。

  • Asp.Net实现Comet

有了技术基础那么来看看如何实现这项技术:

在客户端我们需要实现发送请求,这方面可以通过Ajax技术来实现,可以通过javascript比较简单方便的实现异步请求操作。

在服务端监听专门的请求类型,通过实现IhttpAsyncHandler处理请求,BeginProcessRequest方法中有个AsyncCallback类型的参数cb,这是个回调函数,在asp.net中如果不调用这个回调函数cb则不会响应请求,即不会向客户端返回内容,这就实现长连接。直到服务端有数据需要返回给客户端,服务端再调用cb函数以触发执行EndProcessRequest方法,此时客户端才会接收到响应包。

在客户端接收完数据后可以继续向服务端发起请求,重复这个过程就可以模拟出一个长连接的状态。

AspComet组件介绍

在asp.net里有个开源的组件AspComet比较好的实现了Comet,此组件的开源站点:https://github.com/nmosafi/aspcomet。

在AspComet中的核心主要是通过Ajax发起请求,在服务端基于IhttpAsyncHandler来处理请求,通过一个消息总线处理了一整套的Web推技术。组件分为服务端和客户端两部分,都具备良好的扩展性,服务端有比较灵活的委托处理,也可以通过自己继承实现改写自己需要的业务处理,非常方便的二次开发。而客户端也提供了良好的封装性,支持多种主流js脚本库,如Jquery,dojo等,在官方的demo中就提供了这两种脚本库的实现。

在阅读了Aspcomet的源代码后还是比较感叹的,虽然看起来很费劲,但也着实感觉到了这套代码对二次开发提供了很好的支持。基本都是面向对象来实现了整个组件,即使是JS也应用了很多的设计模式。下面就这个组件的主要实现做一些介绍:

服务端


1、首先必须实现IhttpAsyncHandler接口

CometHttpHandler:IhttpAsyncHandler,此类就是用于异步请求的处理单元,简单的说就是服务端的入口。在这里通过BeginProcessRequest方法将请求的内容hold住,同时也将callback也Hold住。当然这里有个重点要注意就是MessageBus,所有消息如何hold住就得看它的了,因为有些消息是要即刻返回给客户端的,而有些是要经过消息总线处理后再转发的,也有的是要留下来作为长连接的。具体的会在讲消息总线时再说明。

最终CometHttpHandler会在请求需要结束时调用EndProcessRequest方法,从而将消息返回给一直等待的连接,客户端会接收并处理此请求的响应包。

CometHttpHandler就是实现了一个入口和出口,通过IhttpAsyncHandler的异步处理能力从而实现了长连接状态。

2、消息封包

对于客户端和服务端之间交互必须有一个消息封包,否则双方无法做一些约定,毕竟Http协议是松散的无状态性。在AspComet中实现了一个类:Message

这个类AspComet的开发者叫其:bauyeuxmessage(介绍),貌似是Dojo提出的一套协议。

在这个消息封包中主要介绍几个:

Channel:消息频道,用于消息广播所在的频道

clientId:客户端的id

data:数据封包(就是一个object类型,很容易用于扩展的数据包)

version:版本号,这块对消息的向下兼容很有作用

advice:返回后的处理方式,叫通知也可

timestamp:时间戳

ext:貌似是扩展用的

封包的内容很丰富,有时候协议就是种约定,其实对于我们来说就是一个类嘛,甚至于你可以理解就是一个字符串,客户端和服务端通过某种约定可以相互解析识别就可。

3、消息总线设计

在说到IhttpAnyscHandler时就提到了消息总线,在AspComet中抽象为一个接口:IMessageBus。

public interface IMessageBus{void HandleMessages(Message[] messages, ICometAsyncResult cometAsyncResult);}

就一个方法,这也就是AspComet用于处理消息的核心方法了,方法的意思就是处理消息,在这个方法里主要是将接收的消息分配给不同的消息处理者进行处理,比如:发起握手协议时要将消息给MetaHandshakeHandler来处理,这就是一个消息中转中心。

参数messages是消息封包,因为可能是多个消息所以用了数组。

参数cometAsyncResult是对异步请求回调函数的一个二次封装,主要目的是将callback给接住,不让其响应,这样就可以控制什么时候返回响应包了。ICometAsyncResult接口就两个方法

SendAwaitingMessages是用于将发送等待的消息,主要是用于将要发送的消息写入到发送管道中

CompleteRequestWithMessages是用于完成请求的过程,主要是调一下callback以告诉IhttpAsyncHandler请求可以返回啦

通过这两个方法的配合就可以实现将消息向客户端发送消息啦。

这里提一点:其实向客户端发送数据的方法很简单,Http分请求包和响应包,客户端发给服务端的叫请求(Request),服务端发给客户端的叫响应(Response),这下应该明白了吧。SendAwaitingMessages就是把数据写入到Response里,这样客户端不就有接收的数据了吗?

4、各类型消息的处理

在消息总线里提到了消息处理者,为什么会有这个东东存在呢?其实这跟整个的通信过程有关,有握手过程、连接建立过程、断开过程等等,这就要有一整套处理的方法,也就是要对每种不同的过程做一个类型分开处理。在AspComet中有一个接口:ImessageHandler,它定义了一个消息处理的统一方法:

通过继承这个接口实现特定的消息处理类就可以完成一些特定的业务了,下面列举一下各种消息处理类:

MetaHandshakeHandler

握手协议处理

MetaConnectHandler

连接协议处理

MetaDisconnectHandler

断开连接处理

MetaSubscribeHandler

订阅处理

MetaUnsubscribeHandler

停止订阅处理

ForwardingHandler

消息转发处理

ExceptionHandler

异常消息处理

SwallowHandler

吞掉消息处理,不给客户端返回

从字面意思应该就可以理解大体了,发什么消息做什么处理,就这个意思。

说到消息的分类处理有个东西必须说明,在MessageBus中如何区分消息类型并找到对应的处理者呢?这就是和ImessagesProcessor的功劳了。

在这个接口中Process方法就是用于处理每条消息的转发,这个设计也很好,我们甚至可以实现一个自己的MessagesProcessor完全按自己的要求进行消息转发和处理。在此我还是看一下官方的默认实现吧,在AspComet组件中有个默认的实现MessagesProcessor,代码如下:

在代码中可以看到,MessageProcessor是通过一个HandlerFactory来获取实际的ImessageHandler实例,进而处理消息的,这个过程也不复杂,官方提供的实现就是MessageHandlerFactory类:

在这里处理的方法是根据channel的不同调用相应的handler。

回到ImessageHandler,就得说明一下AspComet对单独消息处理时释放出来的委托设计,在Handler执行Handlemessage方法时会调用相应的委托,外部程序可以订阅委托实现进行一些处理。比如我在握手过程中验证客户端合法性,但这个客户端的合法性需要外部应用程序才能检验,怎么办呢?就可以通过MetaHandshakeHandler中HandleMessage方法释放出来的两个委托进行处理,代码如下:

在这段代码里有两个EventHub.Publish(…)的调用,这就是两个委托调用,我们要实现客户端合法性验证就要在第一个委托时做处理,比如上面代码中有两行这样的代码:

这就是调用一个委托,参数是handshakingEvent。外部订阅此委托的程序会处理相应的逻辑,如果不符合要求则将其Cancel属性设置为true,就说明本次消息发送过程要取消掉,并且可以写入相应的原因。下面是一个实现的例子:

CheckHandshake方法就是订阅了委托的方法,其中的参数就是从EventHub.Publish(handshakingEvent);中传过来的。在CheckHandshake里可以取得相应的Client对象并做一些检查等,如果不符合要求可以将ev.Cancel设置为true,并将原因写入CancellationReason属性发回给客户端。

5、客户端对象管理

在服务端要管理客户端的信息,这样才能在消息广播时向特定的客户端发送,为了保持客户端的应用无关性,AspComet定义了Iclient接口:

Iclient说明

这里定义了对Client的一些基础定义,继承此接口实现一个客户端类就行了。

这里所说有客户端并非指的实际的浏览器端