您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 纺织服装 > Comet 的 Web 应用
1使用Java实现Comet风格的Web应用源地址:实现Servlet3.0规范MichaelGalpin,软件架构师,eBay简介:探索Comet开发的不同实现。看看Jetty和Tomcat之类的流行Java™Web服务器如何支持Comet应用程序,并了解如何为不同的服务器编程。最后,了解Java中有关Comet的标准化建议,这些建议是即将到来的Servlet3.0和JavaEE6规范的一部分。标记本文!发布日期:2009年7月22日级别:中级其他语言版本:英文访问情况3539次浏览建议:0(添加评论)平均分(共6个评分)开始在本文中,我将展示如何使用各种不同的Java技术构建一些简单的Comet风格的Web应用程序。读者对Javaservlet、Ajax和JavaScript应该有一定的了解。我们将考察Tomcat和Jetty中一些支持Comet的特性,因此需要使用这两个产品的最新版本。本文使用Tomcat6.0.14和Jetty6.1.14。另外还需要一个支持Java5或更高版本的JDK。本文使用JDK1.5.0-16。此外还需要看看Jetty7的预发布版,因为它实现了Servlet3.0规范,我们将在本文中研究该规范。请参阅参考资料,找到下载链接。回页首理解Comet您可能已经听说过Comet,因为它最近受到了一定的关注。Comet有时也称反向Ajax或服务器端推技术(server-sidepush)。其思想很简单:将数据直接从服务器推到浏览器,而不必等到浏览器请求数据。听起来简单,但是如果熟悉Web应用程序,尤其是HTTP协议,那么您就会知道,这绝不简单。实现Comet风格的Web应用程序,同时保证在浏览器和服务器上的可伸缩性,这只是在最近几年才成为可能。在本文的后面,我们将看看一些流行的JavaWeb服务器如何支持可伸缩的Comet架构,但首先我们来看看为什么要创建Comet应用程序,以及用于实现它们的常见设计模式。使用Comet的动机HTTP协议的成功毋庸置疑。它是Internet上大部分信息交换的基础。然而,它也有一些局限性。特别是,它是无状态、单向的协议。请求被发送到Web服务器,服务器处理请求并发回一个响应—仅此而已。请求必须由客户机发出,而服务器则只能在对请求的响应中发送数据。这至少会影响很多类型的Web应用程序的实用性。典型的例子就是聊天程序。另外还有一些例子,例如比赛的比分、股票行情或电子邮件程序。HTTP的这些局限性也是它取得一定成功的原因。请求/响应周期使它成为了经典的模型,即每个连接使用一个线程。只要能够快速为请求提供服务,这种方法就有巨大的可伸缩性。每秒钟可以处理大量的请求,只需使用少量的服务器就可以处理很大数量的用户。对于很多经典的Web应用程序,例如内容管理系统、搜索应用程序和电子商务站点等等而言,这非常适合。在以上任何一种Web应用程序中,服务器提供用户请求的数据,然后关闭连接,并释放那个线程,使之可以为其他请求服务。如果提供初始数据之后仍可能存在交互,那么将连接保持为打开状态,因此线程就不能释放出来,服务器也就不能为很多用户服务。但是,如果想在对请求做出响应并发送初始数据之后,仍然保持与用户的交互呢?在Web早期,这一点常使用meta刷新实现。这将自动指示浏览器在指定秒数之后重新装载页面,从而支持简陋的轮询(polling)。这不仅是一种糟糕的用户体验,而且通常效率非常低下。如果没有新的数据要显示在页面上呢?这时不得不重新呈现同样的页面。如果对页面的更改很少,并且页面的大部分没有变化呢?同样,不管是否有必要,都得重新请求和获取页面上的一切内容。Ajax的发明和流行改变了上述状况。现在,服务器可以异步通信,因此不必重新请求整个页面。现在可以进行增量式的更新。只需使用XMLHttpRequest轮询服务器。这项技术通常被称作Comet。这项技术存在一些变体,每种变体具有不同的性能和可伸缩性。我们来看看这些不同风格的Comet。Comet风格Ajax的出现使Comet成为可能。HTTP的单向性质可以有效地加以规避。实际上有一些不同的方法可以绕过这一点。您可能已经猜到,支持Comet的最容易的方式是轮询(poll)。使用XMLHttpRequest向服务器发出调用,返回后,等待一段固定的时间(通常使用JavaScript的setTimeout函数),然后再次调用。这是一项非常常见的技术。例如,大多数webmail应用程序就是通过这种技术在电子邮件到达时显示电子邮件的。这项技术有优点也有缺点。在这种情况下,您期望快速返回响应,就像任何其他Ajax请求一样。在请求之间必须有一段暂停。否则,连续不断的请求会冲垮服务器,并且这种情况下显然不具有可伸缩性。这段暂停使应用程序产生一个延时。暂停的时间越长,服务器上的新数据就需要越多的时间才能到达客户机。如果缩短暂停时间,又将重新面临冲垮服务器的风险。但是另一方面,这显然是最简单的实现Comet的方式。现在应该指出,很多人认为轮询并不属于Comet。相反,他们认为Comet是对轮询的局限性的一个解决方案。最常见的“真正的”Comet技术是轮询的一种变体,即长轮询(longpolling)。轮询与长轮询之间的主要区别在于服务器花多长的时间作出响应。长轮询通常将连接保持一段较长的时间—通常是数秒钟,但是也可能是一分钟甚至更长。当服务器上发生某个事件时,响应被发送并随即关闭,轮询立即重新开始。长轮询相对于一般轮询的优点在于,数据一旦可用,便立即从服务器发送到客户机。请求可能等待较长的时间,期间没有任何数据返回,但是一旦有了新的数据,它将立即被发送到客户机。因此没有延时。如果您使用过基于Web的聊天程序,或者声称“实时”的任何程序,那么它很可能就是使用了这种技术。长轮询有一种变体,这是第三种风格的Comet。这通常被称为流(streaming)。按照这种风格,服务器将数据推回客户机,但是不关闭连接。连接将一直保持开启,直到过期,并导致重新发出请求。XMLHttpRequest规范表明,可以检查readyState的值是否为3或Receiving(而不是4或Loaded),并获取正从服务器“流出”的数据。和长轮询一样,这种方式也没有延时。当服务器上的数据就绪时,该数据被发送到客户机。这种方式的另一个优点是可以大大减少发送到服务器的请求,从而避免了与设置服务器连接相关的开销和延时。不幸的是,XMLHttpRequest在不同的浏览器中有很多不同的实现。这项技术只能在较新版本的MozillaFirefox中可靠地使用。对于InternetExplorer或Safari,仍需使用长轮询。至此,您可能会想,长轮询和流都有一个很大的问题。请求需要在服务器上存在一段较长的时间。这打破了每个请求使用一个线程的模型,因为用于一个请求的线程一直没有被释放。更糟糕的是,除非要发回数据,否则该线程一直处于空闲状态。这显然不具有可伸缩性。幸运的是,现代JavaWeb服务器有很多方式可以解决这个问题。回页首Java中的Comet现在有很多Web服务器是用Java构建的。一个原因是Java有一个丰富的本地线程模型。因此实现典型的每个连接一个线程的模型便非常简单。该模型对于Comet不大适用,但是,Java对此同样有解决的办法。为了有效地处理Comet,需要非阻塞IO,Java通过它的NIO库提供非阻塞IO。两种最流行的开源服务器ApacheTomcat和Jetty都利用NIO增加非阻塞IO,从而支持Comet。然而,这两种服务器中的实现却各不相同。我们来看看Tomcat和Jetty对Comet的支持。Tomcat和Comet对于ApacheTomcat,要使用Comet,主要需要做两件事。首先,需要对Tomcat的配置文件server.xml稍作修改。默认情况下启用的是更典型的同步IO连接器。现在只需将它切换成异步版本,如清单1所示。清单1.修改Tomcat的server.xml!--ThisistheusualConnector,commentitoutandaddtheNIOone--!--ConnectorURIEncoding=utf-8connectionTimeout=20000port=8084protocol=HTTP/1.1redirectPort=8443/--ConnectorconnectionTimeout=20000port=8080protocol=org.apache.coyote.http11.Http11NioProtocolredirectPort=8443/这使Tomcat可以处理更多的并发连接,但需要说明的是,其中大多数连接有很多时间都处于空闲状态。利用这一点的最容易的方式是创建一个实现org.apache.catalina.CometProcessor接口的servlet。这显然是Tomcat特有的一个接口。清单2显示了一个这样的例子。清单2.TomcatCometservletpublicclassTomcatWeatherServletextendsHttpServletimplementsCometProcessor{privateMessageSendermessageSender=null;privatestaticfinalIntegerTIMEOUT=60*1000;@Overridepublicvoiddestroy(){messageSender.stop();messageSender=null;}@Overridepublicvoidinit()throwsServletException{messageSender=newMessageSender();ThreadmessageSenderThread=newThread(messageSender,MessageSender[+getServletContext().getContextPath()+]);messageSenderThread.setDaemon(true);messageSenderThread.start();}publicvoidevent(finalCometEventevent)throwsIOException,ServletException{HttpServletRequestrequest=event.getHttpServletRequest();HttpServletResponseresponse=event.getHttpServletResponse();if(event.getEventType()==CometEvent.EventType.BEGIN){request.setAttribute(org.apache.tomcat.comet.timeout,TIMEOUT);log(Beginforsession:+request.getSession(true).getId());messageSender.setConnection(response);Weathermanweatherman=newWeatherman(95118,32408);newThread(weatherman).start();}elseif(event.getEventType()==CometEvent.EventType.ERROR){log(Errorforsession:+request.getSession(true).getId());event.close();}elseif(event.getEventType()==CometEvent.EventType.END){log(Endforsession:+request.getSession(true).getId());event.cl
本文标题:Comet 的 Web 应用
链接地址:https://www.777doc.com/doc-4437051 .html