CometQ基?HTTP 长连接的“服务器推”技?br />
2008-06-30 21:31
别: 中
??(zhouting@cn.ibm.com), 软g工程? IBM 中国软g开发技术实验室
2007 q?8 ?31 ?/p>
很多应用譬如监控、即旉信、即时报Ll都需要将后台发生的变化实时传送到客户端而无dL不停地刷新、发送请求。本文首先介l、比较了常用?#8220;服务器推”ҎQ着重介l了 Comet Q?使用 HTTP 长连接、无L览器安装插g的两U?#8220;服务器推”ҎQ基?AJAX 的长轮询方式Q基?iframe ?htmlfile 的流方式。最后分析了开?Comet 应用需要注意的一些问题,以及如何借助开源的 Comet 框架Qpushlet 构徏自己?#8220;服务器推”应用?br />
“服务器推”技术的应用
误?Ajax 技术资源中心,q是有关 Ajax ~程模型信息的一站式中心Q包括很多文档、教E、论坛、blog、wiki 和新闅RQ?Ajax 的新信息都能在这里找到?nbsp;
订阅 Ajax 相关文章和教E的 RSS 提要
传统模式?Web pȝ以客L发出h、服务器端响应的方式工作。这U方式ƈ不能满很多现实应用的需求,譬如Q?/p>
监控pȝQ后台硬件热插拔、LED、温度、电压发生变化;
x通信pȝQ其它用L录、发送信息;
x报hpȝQ后台数据库内容发生变化Q?
q些应用都需要服务器能实时地更新的信息传送到客户端,而无dL发出h?#8220;服务器推”技术在现实应用中有一些解x案,本文这些解x案分Zc:一c需要在览器端安装插gQ基于套接口传送信息,或是使用 RMI、CORBA q行q程调用Q而另一cd无须览器安装Q何插件、基?HTTP 长连接?/p>
?#8220;服务器推”应用?Web E序中,首先考虑的是如何在功能有限的览器端接收、处理信息:
客户端如何接收、处理信息,是否需要用套接口或是使用q程调用。客L呈现l用L?HTML 面q是 Java applet ?Flash H口。如果用套接口和远E调用,怎么?JavaScript l合修改 HTML 的显C?
客户与服务器端通信的信息格式,采取怎样的出错处理机制?
客户端是否需要支持不同类型的览器如 IE、FirefoxQ是否需要同时支?Windows ?Linux q_?
回页?
Z客户端套接口?#8220;服务器推”技?/p>
Flash XMLSocket
如果 Web 应用的用h受应用只有在安装?Flash 播放器才能正常运行, 那么使用 Flash ?XMLSocket 也是一个可行的Ҏ?/p>
q种Ҏ实现的基是:
Flash 提供?XMLSocket cR?
JavaScript ?Flash 的紧密结合:?JavaScript 可以直接调用 Flash E序提供的接口?
具体实现ҎQ在 HTML 面中内嵌入一个用了 XMLSocket cȝ Flash E序。JavaScript 通过调用?Flash E序提供的套接口接口与服务器端的套接口进行通信。JavaScript 在收到服务器端以 XML 格式传送的信息后可以很Ҏ地控?HTML 面的内ҎC?/p>
关于如何L建充当了 JavaScript ?Flash XMLSocket 桥梁?Flash E序Q以及如何在 JavaScript 里调?Flash 提供的接口,我们可以参?AFLAXQAsynchronous Flash and XMLQ项目提供的 Socket Demo 以及 SocketJSQ请参见 参考资源)?/p>
Javascript ?Flash 的紧密结合,极大增强了客L的处理能力。从 Flash 播放?V7.0.19 开始,已经取消?XMLSocket 的端口必d?1023 的限制。Linux q_也支?Flash XMLSocket Ҏ。但此方案的~点在于Q?/p>
客户端必d?Flash 播放器;
因ؓ XMLSocket 没有 HTTP 隧道功能QXMLSocket cM能自动穿q防火墙Q?
因ؓ是用套接口Q需要设|一个通信端口Q防火墙、代理服务器也可能对?HTTP 通道端口q行限制Q?
不过q种Ҏ在一些网l聊天室Q网l互动游戏中已得到广泛用?/p>
Java Applet 套接?
在客L使用 Java AppletQ通过 java.net.Socket ?java.net.DatagramSocket ?java.net.MulticastSocket 建立与服务器端的套接口连接,从而实?#8220;服务器推”?/p>
q种Ҏ最大的不在于 Java applet 在收到服务器端返回的信息后,无法通过 JavaScript L?HTML 面的内宏V?/p>
回页?
Z HTTP 长连接的“服务器推”技?/p>
Comet ?/p>
览器作?Web 应用的前収ͼ自n的处理功能比较有限。浏览器的发展需要客L升软gQ同时由于客L览器Y件的多样性,在某U意义上Q也影响了浏览器新技术的推广。在 Web 应用中,览器的主要工作是发送请求、解析服务器q回的信息以不同的风格显C。AJAX 是浏览器技术发展的成果Q通过在浏览器端发送异步请求,提高了单用户操作的响应性。但 Web 本质上是一个多用户的系l,对Q何用h_可以认ؓ服务器是另外一个用戗现?AJAX 技术的发展q不能解军_一个多用户?Web 应用中,更新的信息实时传送给客户端,从而用户可能在“q时”的信息下q行操作。?AJAX 的应用又使后台数据更新更加频J成为可能?/p>
?1. 传统?Web 应用模型与基?AJAX 的模型之比较
“服务器推”是一U很早就存在的技术,以前在实C主要是通过客户端的套接口,或是服务器端的远E调用。因为浏览器技术的发展比较~慢Q没有ؓ“服务器推”的实现提供很好的支持Q在U浏览器的应用中很难有一个完善的Ҏd?#8220;服务器推”q用于商业程序。最q几q_因ؓ AJAX 技术的普及Q以及把 IFrame 嵌在“htmlfile“?ActiveX lg中可以解?IE 的加载显C问题,一些受Ƣ迎的应用如 meeboQgmail+gtalk 在实C使用了这些新技术;同时“服务器推”在现实应用中实存在很多需求。因些原因,ZU浏览器?#8220;服务器推”技术开始受到较多关注,Alex RussellQDojo Toolkit 的项?LeadQ称q种Z HTTP 长连接、无d览器端安装插g?#8220;服务器推”技术ؓ“Comet”。目前已l出C一些成熟的 Comet 应用以及各种开源框Ӟ一?Web 服务器如 Jetty 也在为支持大量ƈ发的长连接进行了很多改进。关?Comet 技术最新的发展状况请参考关?Comet ?wiki?/p>
下面介l两U?Comet 应用的实现模型?/p>
Z AJAX 的长轮询Qlong-pollingQ方?/p>
??1 所C,AJAX 的出C?JavaScript 可以调用 XMLHttpRequest 对象发出 HTTP hQJavaScript 响应处理函数Ҏ服务器返回的信息?HTML 面的显C行更新。?AJAX 实现“服务器推”与传l的 AJAX 应用不同之处在于Q?/p>
服务器端会阻塞请求直到有数据传递或时才返回?
客户?JavaScript 响应处理函数会在处理完服务器q回的信息后Q再ơ发求,重新建立q接?
当客L处理接收的数据、重新徏立连接时Q服务器端可能有新的数据到达Q这些信息会被服务器端保存直到客L重新建立q接Q客L会一ơ把当前服务器端所有的信息取回?
?2. Z长轮询的服务器推模型
一些应用及CZ?“Meebo”, “Pushlet Chat” 都采用了q种长轮询的方式。相对于“轮询”QpollQ,q种长轮询方式也可以UCؓ“?#8221;QpullQ。因U方案基?AJAXQ具有以下一些优点:h异步发出Q无d装插ӞIE、Mozilla FireFox 都支?AJAX?/p>
在这U长轮询方式下,客户端是?XMLHttpRequest ?readystate ?4Q即数据传输l束Q时调用回调函数Q进行信息处理。当 readystate ?4 Ӟ数据传输l束Q连接已l关闭。Mozilla Firefox 提供了对 Streaming AJAX 的支持, ?readystate ?3 Ӟ数据仍在传输中)Q客L可以d数据Q从而无d闭连接,pd处理服务器端q回的信息。IE ?readystate ?3 Ӟ不能d服务器返回的数据Q目?IE 不支持基?Streaming AJAX?/p>
Z Iframe ?htmlfile 的流QstreamingQ方?/p>
iframe 是很早就存在的一U?HTML 标记Q?通过?HTML 面里嵌入一个隐蔵Q然后将q个隐蔵帧的 SRC 属性设为对一个长q接的请求,服务器端p源源不断地往客户端输入数据?/p>
?3. Z方式的服务器推模型
上节提到?AJAX Ҏ是在 JavaScript 里处?XMLHttpRequest 从服务器取回的数据,然后 Javascript 可以很方便的L?HTML 面的显C。同L思\用在 iframe Ҏ的客LQiframe 服务器端q不q回直接昄在页面的数据Q而是q回对客L Javascript 函数的调用,?#8220;<script type="text/javascript">js_func(“data from server ”)</script>”。服务器端将q回的数据作为客L JavaScript 函数的参C递;客户端浏览器?Javascript 引擎在收到服务器q回?JavaScript 调用时就会去执行代码?/p>
??3 可以看到Q每ơ数据传送不会关闭连接,q接只会在通信出现错误Ӟ或是q接重徏时关闭(一些防火墙常被讄Z弃过长的q接Q?服务器端可以讄一个超时时_ 时后通知客户端重新徏立连接,q关闭原来的q接Q?/p>
使用 iframe h一个长q接有一个很明显的不之处:IE、Morzilla Firefox 下端的进度栏都会昄加蝲没有完成Q而且 IE 上方的图标会不停的{动,表示加蝲正在q行。Google 的天才们使用一个称?#8220;htmlfile”?ActiveX 解决了在 IE 中的加蝲昄问题Qƈ这U方法用C gmail+gtalk 产品中。Alex Russell ?“What else is burried down in the depth's of Google's amazing JavaScript?”文章中介l了q种Ҏ。Zeitoun |站提供?comet-iframe.tar.gzQ封装了一个基?iframe ?htmlfile ?JavaScript comet 对象Q支?IE、Mozilla Firefox 览器,可以作ؓ参考。(请参?参考资源)
回页?
使用 Comet 模型开发自q应用
上面介绍了两U基?HTTP 长连接的“服务器推”架构Q更多描qC客户端处理长q接的技术。对于一个实际的应用而言Q系l的E_性和性能是非帔R要的。将 HTTP 长连接用于实际应用,很多l节需要考虑?/p>
不要在同一客户端同时用超q两个的 HTTP 长连?/p>
我们使用 IE 下蝲文g时会有这L体验Q从同一?Web 服务器下载文Ӟ最多只能有两个文g同时被下载。第三个文g的下载会被阻塞,直到前面下蝲的文件下载完毕。这是因?HTTP 1.1 规范中规定,客户端不应该与服务器端徏立超q两个的 HTTP q接Q?新的q接会被d。?IE 在实C严格遵守了这U规定?/p>
HTTP 1.1 对两个长q接的限Ӟ会对使用了长q接?Web 应用带来如下现象Q在客户端如果打开过两个?IE H口去访问同一个用了长连接的 Web 服务器,W三?IE H口?HTTP h被前两个H口的长q接d?/p>
所以在开发长q接的应用时Q?必须注意在用了多个 frame 的页面中Q不要ؓ每个 frame 的页面都建立一?HTTP 长连接,q样会阻塞其它的 HTTP hQ在设计上考虑让多?frame 的更新共用一个长q接?/p>
服务器端的性能和可扩展?/p>
一?Web 服务器会为每个连接创Z个线E,如果在大型的商业应用中?CometQ服务器端需要维护大量ƈ发的长连接。在q种应用背景下,服务器端需要考虑负蝲均衡和集技术;或是在服务器端ؓ长连接作一些改q?/p>
应用和技术的发展L带来新的需求,从而推动新技术的发展。HTTP 1.1 ?1.0 规范有一个很大的不同Q?.0 规范下服务器在处理完每个 Get/Post h后会关闭套接口连接; ?1.1 规范下服务器会保持这个连接,在处理两个请求的间隔旉里,q个q接处于I闲状态?Java 1.4 引入了支持异?IO ?java.nio 包。当q接处于I闲Ӟ个连接分配的U程资源会返q到U程池,可以供新的连接用;当原来处于空闲的q接的客户发出新的请求,会从U程池里分配一个线E资源处理这个请求?q种技术在q接处于I闲的机率较高、ƈ发连接数目很多的场景下对于降低服务器的资源负载非常有效?/p>
但是 AJAX 的应用h的出现变得频J,?Comet 则会长时间占用一个连接,上述的服务器模型在新的应用背景下会变得非怽效,U程池里有限的线E数甚至可能会阻塞新的连接。Jetty 6 Web 服务器针?AJAX、Comet 应用的特点进行了很多创新的改q,请参考文?#8220;AJAXQComet and Jetty”Q请参见 参考资源)?/p>
控制信息与数据信息用不同的 HTTP q接
使用长连接时Q存在一个很常见的场景:客户端网需要关闭,而服务器端还处在d数据的堵塞状态,客户端需要及旉知服务器端关闭数据q接。服务器在收到关闭请求后首先要从d数据的阻塞状态唤醒,然后释放个客L分配的资源,再关闭连接?/p>
所以在设计上,我们需要客户端的控制h和数据请求用不同的 HTTP q接Q才能控制h不会被阻塞?/p>
在实CQ如果是Z iframe 方式的长连接,客户端页面需要用两?iframeQ一个是控制帧,用于往服务器端发送控制请求,控制h能很快收到响应,不会被堵塞;一个是昄帧,用于往服务器端发送长q接h。如果是Z AJAX 的长轮询方式Q客L可以异步地发Z?XMLHttpRequest hQ通知服务器端关闭数据q接?/p>
在客户和服务器之间保?#8220;心蟩”信息
在浏览器与服务器之间l持一个长q接会ؓ通信带来一些不定性:因ؓ数据传输是随机的Q客L不知道何时服务器才有数据传送。服务器端需要确保当客户端不再工作时Q释放ؓq个客户端分配的资源Q防止内存泄漏。因此需要一U机制双方知道大家都在正常q行。在实现上:
服务器端在阻塞读时会讄一个时限,时后阻塞读调用会返回,同时发给客户端没有新数据到达的心跳信息。此时如果客L已经关闭Q服务器往通道写数据会出现异常Q服务器端就会及旉放ؓq个客户端分配的资源?
如果客户端用的是基?AJAX 的长轮询方式Q服务器端返回数据、关闭连接后Q经q某个时限没有收到客L的再ơ请求,会认为客L不能正常工作Q会释放个客L分配、维护的资源?
当服务器处理信息出现异常情况Q需要发送错误信息通知客户端,同时释放资源、关闭连接?
Pushlet - 开?Comet 框架
Pushlet 是一个开源的 Comet 框架Q在设计上有很多值得借鉴的地方,对于开发轻量?Comet 应用很有参考h倹{?/p>
观察者模?/p>
Pushlet 使用了观察者模型:客户端发送请求,订阅感兴的事gQ服务器端ؓ每个客户端分配一个会?ID 作ؓ标记Q事件源会把C生的事g以多播的方式发送到订阅者的事g队列里?/p>
客户?JavaScript ?/p>
pushlet 提供了基?AJAX ?JavaScript 库文件用于实现长轮询方式?#8220;服务器推”Q还提供了基?iframe ?JavaScript 库文件用于实现流方式?#8220;服务器推”?/p>
JavaScript 库做了很多封装工作:
定义客户端的通信状态:STATE_ERROR、STATE_ABORT、STATE_NULL、STATE_READY、STATE_JOINED、STATE_LISTENINGQ?
保存服务器分配的会话 IDQ在建立q接之后的每ơ请求中会附上会?ID 表明w䆾Q?
提供?join()、leave()、subscribe()?unsubsribe()、listen() {?API 供页面调用;
提供了处理响应的 JavaScript 函数接口 onData()、onEvent()…
|页可以很方便地使用q两?JavaScript 库文件封装的 API 与服务器q行通信?/p>
客户端与服务器端通信信息格式
pushlet 定义了一套客户与服务器通信的信息格式,使用 XML 格式。定义了客户端发送请求的cdQjoin、leave、subscribe、unsubscribe、listen、refreshQ以及响应的事gcdQdata、join_ack、listen_ack、refresh、heartbeat、error、abort、subscribe_ack、unsubscribe_ack?/p>
服务器端事g队列理
pushlet 在服务器端?Java Servlet 实现Q其数据l构的设计框架仍可适用?PHP、C ~写的后台客L?/p>
Pushlet 支持客户端自己选择使用、拉Q长轮询Q、轮询方式。服务器端根据客户选择的方式在d事g队列QfetchEventsQ时q行不同的处理?#8220;轮询”模式?fetchEvents() 会马上返回?#8221;?#8220;?#8221;?#8220;模式使用d的方式读事gQ如果超Ӟ会发l客L发送一个没有新信息收到?#8220;heartbeat“事gQ如果是“?#8221;模式Q会?#8220;heartbeat”?#8220;refresh”事g一起传l客LQ通知客户端重新发求、徏立连接?/p>
客户服务器之间的会话理
服务端在客户端发?join hӞ会ؓ客户端分配一个会?IDQ?q传l客LQ然后客L通过此会?ID 标明w䆾发出 subscribe ?listen h。服务器端会为每个会话维护一个订阅的主题集合、事仉列?/p>
服务器端的事件源会把C生的事g以多播的方式发送到每个会话Q即订阅者)的事仉列里?/p>
回页?
结
本文介绍了如何在现有的技术基上选择合适的Ҏ开发一?#8220;服务器推”的应用,最优的Ҏq是取决于应用需求的本n。相对于传统?Web 应用Q?目前开?Comet 应用q是h一定的挑战性?/p>
“服务器推”存在q泛的应用需求,Z?Comet 模型适用于大规模的商业应用,以及方便用户构徏 Comet 应用Q最q几q_无论是服务器q是览器都出现了很多新技术,同时也出C很多开源的 Comet 框架、协议。需求推动技术的发展Q相?Comet 的应用会变得?AJAX 一h及?/p>
参考资?
学习
developerWorks 文章“ 面向 Java 开发h员的 Ajax: 使用 Jetty ?Direct Web Remoting ~写可扩展的 Comet 应用E序”Q受异步服务器端事g驱动?Ajax 应用E序实现较ؓ困难Q本文介l了一U结合?Comet 模式?Jetty 6 Continuations API 的解x法?
“Comet: Low Latency Data for the Browser”QAlex Russell ?Dojo Toolkit 的项目主和 Dojo Foundation 的主席,他在q篇博客文章中提Z Comet q个术语?
“What else is burried down in the depth’s of Google’s amazing JavaScript?”QAlex RusselQ?006 q?2 月)QAlex 在这文章里介绍了如何?#8220;htmlfile”ActiveX 控g解决 iframe h长连接时 IE 的加载显C问题?
Comet wikiQ提供了很多开?Comet 框架的链接?
JettyQJetty 是一U开源的Z标准?Web 服务器,完全使用 Java 语言实现?
“Ajax, Comet and Jetty”QGreg WilkinsQWebtideQ?006 q?1 月)QWilkins 的这份白皮书讨论了扩?Ajax q接?Jetty 架构Ҏ?
ContinuationsQ了解更多关?Jetty ?Continuations Ҏ的信息?
“pushlet”Q开?comet 框架Q用了观察者模型。浏览器端提供了Z AJAX ?iframe ?JavaScript 库,服务器端使用 Java Servlet?
“How to implement COMET with PHP”Q提供的 comet-iframe.tar.gz 使用 iframe/htmlfile 装了一?JavaScript comet 对象Q支?IE、Mozilla Firefox 览器?
“AFLAX”QAsynchronous Flash and XMLQ提供了强大?Flash、Javascript 库和很多范例?
developerWorks Ajax 技术资源中心:能找到更多关?Ajax 技术的文章和教E?
developerWorks Web 开发技术专区:提供了关?Web 开发和架构斚w的大量文章?
developerWorks Java 技术专区:提供了关?Java ~程各个斚w的数癄文章?
览 技术书店,查阅有关本文所qC题以及其他技术主题的书籍?nbsp;

]]>