comet: 服务器推模式通讯

DWR2.0的推技术:这里有介绍

comet的实现介绍:这里

其中的原理在于维护HTTP长连接,这里有介绍

摘录一部分,说明其原理:

Pushlet基于HTTP流,这种技术常常用在多媒体视频、通讯应用中,比如QuickTime。与装载HTTP页面之后马上关闭HTTP连接的做法相反,Pushlet采用HTTP流方式将新数据源源不断地推送到client,再此期间HTTP连接一直保持打开。有关如何在Java中实现这种Keep-alive的长连接请参看Sun提供的《HTTP Persistent Connection》W3C的《HTTP1.1规范》。
示例1
我们利用HTTP流开发一个JSP页面(因为它易于部署,而且它在web server中也是作为servlet对待的),此页面在一个定时器循环中不断地发送新的HTML内容给client:


<%
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>");
}
%>

在Pushlet源代码中提供了此页面(examples/basics/push-html-stream.jsp)。上面的页面并不是十分有用,因为在我们刷新页面时,新内容机械地、持续不断地被添加到页面中,而不是server端更新的内容。
示例2
现在让我们步入Pushlet工作机理中一探究竟。通过运行Pushlet的示例源代码(examples/basics/ push-js-stream.html),我们会看到这个每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端,此文件内容如下:

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: %>

注意在示例1和示例2中使用JSP时都存在一个问题:一些servlet引擎在某个client离开时会“吃掉”IOException,以至于JSP页面将永不抛出此异常。所以在这种情况下,页面循环将会永远执行下去。而这正是Pushlet实现采用servlet的原因之一:可以捕获到IOException。
在上面代码的第21行中可以看到在一个定时器循环(3秒/周期)中打印了一些HTML并将它们输出到client浏览器。请注意,这里推送的并非HTML而是Javascript!这样做的意义何在?
它把类似“<script language=JavaScript >parent.push('Page 4')</script>”的一行代码推送到浏览器;而具有JavaScript引擎的浏览器可以直接执行收到的每一行代码,并调用parent.push()函数。而代码中的Parent便是浏览器页面中所在Frame的Parent,也就是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>



<!-- frame to display the content pushed by the pushlet -->


<!-- Hidden frame with the pushlet that pushes lines of JavaScript-->

</FRAMESET>

可以看到push-js-stream.html中的push()函数被名为pushletFrame的JSP Frame调用:把传入的参数值写入到displayFrame(此Frame为push-js-stream-display.html)。这是动态HTML的一个小技巧:使用document对象的writeln方法刷新某个Frame或者Window的内容。
于是displayFrame成为了用于显示内容的、真正的视图。displayFrame初始化为黑色背景并显示“wait…”直到来自server的内容被推送过来:

<H1>WAIT...</H1>

这便是Pushlet的基本做法:我们从servlet(或者从示例中的JSP)把JavaScript代码作为HTTP流推送到浏览器。这些代码被浏览器的JavaScript引擎解释并完成一些有趣的工作。于是便轻松地完成了从server端的Java到浏览器中的JavaScript的回调。
上面的示例展示了Pushlet原理,但这里存在一些等待解决的问题和需要增添的特性。于是我建立了一个小型的server端Pushlet框架(其类结构图表将会展示在下面),添加了一些用在client中的JavaScript库。由于client需要依赖更多的DHTML特性(比如Layers),我们将首先粗略地温习一些 DHTML知识。示例代码见examples/dhtml。

你可能感兴趣的:(Comet)