Twitter框架学习二Http长连接技术实现server端push功能-Comet的理论与实战

Comet简介

在学习Twitter的架构中,发现他们广泛使用了Comet技术,基于Http长连接的服务器Push技术,Twitter本身对于数据的实时性要求较高,因此,采用Comet技术可以很好地解决他们的问题。

 

Comet 是一种新的 Web 应用架构。基于这种架构开发的应用中,服务器端会主动以异步的方式向客户端程序推送数据,而不需要客户端显式的发出请求。Comet 架构非常适合事件驱动的 Web 应用,以及对交互性和实时性要求很强的应用,如股票交易行情分析、聊天室和 Web 版在线游戏等。

 

3.基于Comet技术的开源项目Pushlet

 

下面是笔者翻译的关于Pushlet项目的白皮书的内容,原文出自:http://www.pushlets.com/doc/whitepaper-all.html

 

3.1 Pushlet 白皮书

 

PushLets是基于Servlet的Server端直接push数据到浏览器端的技术,这种push技术的实现不使用任何插件(Flash)或者Java Applet。它允许server端直接update web网页。

 

实现server端push功能通常采用Applet,Flash等技术。这些技术比较复杂也难于实现,有防火墙限制,而且需要另外的server的开发工作和维护。

 

Pushlets是基于Servlet的,数据是server端直接push到浏览器端的网页上,这就允许server可以实时地更新网页的内容。浏览器客户端采用JavaScript或者动态HTML技术,可以支持四种以上的浏览器,如NS(NetScape)和IE。这种机制是使用一个servlet的HTTP连接,这个连接会拿回一段JS代码给浏览器,浏览器然后执行这段代码,从而实现了网页端的数据实时更新。通过一个通用的Servlet(Pushlet),浏览器客户端可以订阅那些需要收到事件的主题。无论何时,server 推送一个事件,那些订阅了相关的主题的客户端都会被通知到。事件对象(Event Object)可以以JavaScript(DHTML clients),序列化的Java对象(JSON)或者XML形式返回。

 

3.2 Pushlet项目的初衷

 

这种机制从某种意义上来说是轻量级的,它利用了server的server的连接管理器和线程设备,javax.servlet APIs和标准的Java特性:如通过wait()和notify()机制实现的生产消费模型。

 

也有另外一种程序,需要订阅从server端不断更新的动态内容。如股票的feeds,系统的状态,天气预报和其它的监控程序。这些都遵从观察者模式(发布、订阅模式),由客户端注册订阅server的主题。

 

当页面装载后,我们应该如何通知浏览器端?或者我们应该怎么做,如果我们要实现选择性的部分更新,例如股票系统,通常只需要更新一个item就可以了?

 

3.Server端通知浏览器客户端的可行性方案

 

先让我们假定我们有一个Java的web server,我们要讲server端的数据通知客户端,达到这个功能有三种方式:

 

1)polling

最简单的方案是页面定时刷新,在HTML的Meta标签里加入定时刷新定义,网页每隔指定的时间都会重新刷新页面。

 

2)Server端的Callback

 

3)Messaging(MOM)

这个方案是,applet作为client端通过TCP/IP或者无连接的UDP消息连接,与消息中间件进行交互。你可能使用一个消息中间件产品如IBus,MQSeries(IBM)或者WebLogic Events(BEA)或者开发你自己的自定义消息。

 

4) 讨论

上面的每种解决方案在复杂性,安全,性能,扩展性,浏览器Java的兼容性和限制如防火墙的限制几个方面都有自己的各自的优缺点。哪种是最优化的方案在很大程度上依赖于你的应用程序的需求。例如,当用户需要一个直接的状态交互,例如白板程序,server端callbacks或者Message技术非常适用于这种场景。

 

除了上面的解决方案,我开发了一种技术-轻量级,瘦客户端,不需要applet或者任何插件,直接和脚本和HTML整合,使用标准的HTTP连接可以部署(从理论上)在支持Servlet的server上。当然我这个技术方案不是要取代上面的方案。我的意图是给你增加一种新的选择。做Java架构师或者开发人员,你应该权衡并选择哪种方案才是最适合你的应用程序。


4.Pushlet基础

什么是Pushlet,他们是如何工作的?从原理来看,Pushlets是异常简单的。下面我将展示这些基础知识,同时也会附带一些代码:


1).HTTP流
Pushlets基于HTTP流,它是一种这样的技术:它经常应用在多媒体的浏览上,例如QuickTime。当新的数据Push到client之后,连接保持开启状态,而不是关闭状态。

 

2).Example 1
基于HTTP流的基本理论,我们可以构造一个JSP文件,它定期不断发送新的HTML内容给Client端。

<HTML>
<HEAD>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
   <META HTTP-EQUIV="Pragma" CONTENT="no-cache">
</HEAD>
<BODY BGCOLOR="blue" TEXT="white">
<% 
  int i = 1;
    
  try {
    while (true) {
       out.print("<h1>"+(i++)+"</h1>");
       out.flush();
      
       try {
            Thread.sleep(3000);
       } catch (InterruptedException e) {
       out.print("<h1>"+e+"</h1>");
        }
     }
   } catch (Exception e) {
       out.print("<h1>"+e+"</h1>");
   }
%>
</BODY>
</HTML>

 

在实例页面上点击实例1。这个实例不是很有用,因为pushed的内容需要不断是添加到page上,而我们更加喜欢刷新它。

 

3)Example 2

 

这里我们直接跳到Pushlet的工作原理上。在实例页面点击example 2,可以看到这个页面是每3秒刷新一次的,到这里我们已经完成了工作了吗?

这个实例包含了三个文件: push-js-stream.html, push-js-stream-pusher.jsp 和 push-js-stream-display.html。

push-js-stream.html 是主页面,在HTML FRAME里面包含其它两个页面,让我们跟随事件的路线慢慢看下去。

下面这个文件列举了push-js-stream-pusher.jsp的内容,这个JSP文件是当请求它时,在server上执行的,这个JSP的主体部分代码如下:

7: <% 
  8:   /** Start a line of JavaScript with a function call to parent frame. */
  9:   String jsFunPre = "<script language=JavaScript >parent.push('";
 10:   
 11:   /** End the line of JavaScript */
 12:   String jsFunPost = "')</script> ";
 13:   
 14:   int i = 1;
 15:   try {
 16:   
 17:     // Every three seconds a line of JavaScript is pushed to the client
 18:     while (true) {
 19:     
 20:        // Push a line of JavaScript to the client 
 21:        out.print(jsFunPre+"Page "+(i++)+jsFunPost);
 22:        out.flush();
 23:        
 24:        // Sleep three secs
 25:        try {
 26:             Thread.sleep(3000);
 27:        } catch (InterruptedException e) {
 28:             // Let client display exception 
 29:             out.print(jsFunPre+"InterruptedException: "+e+jsFunPost);
 30:        }
 31:      }
 32:    } catch (Exception e) {
 33:             // Let client display exception 
 34:             out.print(jsFunPre+"Exception: "+e+jsFunPost);
 35:    }
 36: %> 


这里我们又看到了一个定时循环:每3秒钟向浏览器打印了一些HTML代码。但是请注意一点,这个不是push 
HTML,而是JavaScript,这是什么意思?

它push了一行像这样的一行代码:<script language=JavaScript >parent.push('Page 
4')</script>,这对于浏览器是什么意思呢?浏览器有它自己运行的JavaScript引擎,
它会执行每次来的新的JS代码。它是调用parent.push()的JavaScript代码。当前的parent是Frame的Parent,它是我
们刚来list的第一个文件push-js-stream.html,我们再看看这里有什么:
 
<script LANGUAGE="JavaScript"> var pageStart="<HTML><HEAD></HEAD><BODY BGCOLOR=blue TEXT=white><H2>Server pushes: <para>"; var pageEnd="</H2></BODY></HTML>"; // Callback function with message from server. // This function is called from within the hidden JSP pushlet frame function push(content) { // Refresh the display frame with the content received window.frames['displayFrame'].document.writeln(pageStart+content+pageEnd); window.frames['displayFrame'].document.close(); } </script> </HEAD> <FRAMESET BORDER=0 COLS="*,0"> <!-- frame to display the content pushed by the pushlet --> <FRAME SRC="push-js-stream-display.html" NAME="displayFrame" BORDER=0 SCROLLING=no> <!-- Hidden frame with the pushlet that pushes lines of JavaScript--> <FRAME SRC="push-js-stream-pusher.jsp" NAME="pushletFrame" BORDER=0 SCROLLING=no> </FRAMESET>

上面的代码我们可以看到服务端Push过来的Javascript push()方法在哪里得到执行了。

 

这就是Pushlets的基本的原理:我们只是从一个Servlet stream 若干行JS。这些JS被浏览器解释执行。这个例子说明了Pushlet的工作机制,但是仍然有几个问题需要解决。并且需要添加更多的feature。从这个原因来讲,我已经build了一个轻量级的server端的Pushlet框架(如下面的类视图所示),加上几个客户端的JS类库。

 

5.不只是Java-动态HTML
DHTML指的是HTML,CSS,JavaScript和浏览器DOM的融合。传统意义上来讲,只有通过从server重新装载page才能改变page的内容,DHTML允许page装载后仍然能够完全控制一个HTML文档,你也许已经看到了一些web上的实例如image的滚动,弹出内容和折叠菜单。DHTML可以支持4种类型的浏览器。

从程序员角度看,浏览器的dom,例如它的frame,段落,表等等都代表了一种层次性的对象模型-DOM。DHTML允许页面已经装载后能够完全控制一个HTML文档。通过JS,你可以操作DOM,因此你也可以改变document的内容和外观。你可以从这些元素抓取用户事件,如鼠标move,form的提交。例如鼠标滑过一个图片会产生一个mouse-over事件。document元素甚至可以达到动画效果,这看起来很不错,是吧,我们只是需要熟悉DHTML的标准,但是谁定义了DHTML的标准?

 

6.框架的设计
Pushlet框架允许client从server订阅主题,client会相继收到事件。这个框架的基本设计模式是发布-订阅模式,也称作观察者模式,它既有server,又有client的组件。

  • 围绕Pushlet类而设计了server端的集合
  • 在DHTML客户端为了接收事件而设计了可以重用的客户端的JS类库(pushlet.js)
  • 为Java客户端接收事件而设计客户端的Java类(JavaPushletClient.java and JavaPushletClientListener.java)
  • 为显示DHTML层而设计的跨浏览器的DHTML工具库(layer.js, layer-grid.js, layer-region.js)

1). Server-side 类设计图(下面的图只适用于0.04版本)


 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值