清单5. 客户机Comet 代码
<%@page contentType="text/html" pageEncoding="UTF-8"%>
"http://www.w3.org/TR/html4/loose.dtd">
<SCRIPT TYPE="text/java script">
function go(){
var url = "http://localhost:8484/WeatherServer/Weather"
var request = new XMLHttpRequest();
request.open("GET", url, true);
request.setRequestHeader("Content-Type","application/x-java script;");
request.onreadystatechange = function() {
if (request.readyState == 4) {
if (request.status == 200){
if (request.responseText) {
document.getElementById("forecasts").innerHTML =
request.responseText;
}
}
go();
}
};
request.send(null);
}
Rapid Fire Weather
该代码只是在用户单击Go 按钮时开始长轮询。注意,它直接使用XMLHttpRequest 对象,所以这在Internet Explorer 6 中将不能工作。您可能需要使用一个Ajax 库解决浏览器差异问题。除此之外,惟一需要注意的是回调函数,或者为请求的onreadystatechange 函数创建的闭包。该函数粘贴来自服务器的新的数据,然后重新调用go 函数。
现在,我们看过了一个简单的Comet 应用程序在Tomcat 上是什么样的。有两件与Tomcat 密切相关的事情要做:一是配置它的连接器,二是在servlet 中实现一个特定于Tomcat 的接口。您可能想知道,将该代码 “移植” 到Jetty 有多大难度。接下来我们就来看看这个问题。
Jetty 和Comet
Jetty 服务器使用稍微不同的技术来支持Comet 的可伸缩的实现。Jetty 支持被称作continuations 的编程结构。其思想很简单。请求先被暂停,然后在将来的某个时间点再继续。规定时间到期,或者某种有意义的事件发生,都可能导致请求继续。当请求被暂停时,它的线程被释放。
可以使用Jetty 的org.mortbay.util.ajax.ContinuationSupport 类为任何HttpServletRequest 创建org.mortbay.util.ajax.Continuation 的一个实例。这种方法与Comet 有很大的不同。但是,continuations 可用于实现逻辑上等效的Comet。清单6 显示清单2 中的weather servlet “移植” 到Jetty 后的代码。
清单6. Jetty Comet servlet
public class JettyWeatherServlet extends HttpServlet {
private MessageSender messageSender = null;
private static final Integer TIMEOUT = 5 * 1000;
public void begin(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
request.setAttribute("org.apache.tomcat.comet", Boolean.TRUE);
request.setAttribute("org.apache.tomcat.comet.timeout", TIMEOUT);
messageSender.setConnection(response);
Weatherman weatherman = new Weatherman(95118, 32408);
new Thread(weatherman).start();
}
public void end(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
synchronized (request) {
request.removeAttribute("org.apache.tomcat.comet");
Continuation continuation = ContinuationSupport.getContinuation
(request, request);
if (continuation.isPending()) {
continuation.resume();
}
}
}
public void error(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
end(request, response);
}
public boolean read(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
throw new Unsupported