Tomcat的Comet实践

本文介绍如何在Tomcat 8.0中实现Comet技术,包括创建Servlet、配置web.xml及客户端轮询实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

ProtocolHandler接口有一个isCometSupported方法,Comet模式是一种服务器向客户端推数据的方式,由服务器端通过长连接向客户端推送数据,功能跟websocket类似的。

Tomcat的6,7,8.0等版本都支持Comet的,它的catalian.jar中的org.apache.catalina.comet包里面有Comet相关类。但是tomcat8.5版本不知道为什么就不支持comet了,它的catalina包下就没有comet包了。

所以本文实践环境为Eclipse +Tomcat8.0,实现Comet的客户端长轮询。

工程创建

创建一个java web dynamic工程,并将Tomcat8.0的lib目录导入类路径中,需要应用catalina.jar中的CometProcessor,创建一个Servlet类:

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.comet.CometEvent;
import org.apache.catalina.comet.CometProcessor;

public class CometServlet extends HttpServlet implements CometProcessor {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private static final Integer TIMEOUT = 60 * 1000;

    @Override
    public void destroy() {
    }

    @Override
    public void init() throws ServletException {

    }

    @Override
    public void event(CometEvent event) throws IOException, ServletException {
        HttpServletRequest request = event.getHttpServletRequest();
        HttpServletResponse response = event.getHttpServletResponse();
        if (event.getEventType() == CometEvent.EventType.BEGIN) {
            request.setAttribute("org.apache.tomcat.comet.timeout", TIMEOUT);
            log("Begin for session: " + request.getSession(true).getId());
            new CometHandler(response).process();
        } else if (event.getEventType() == CometEvent.EventType.ERROR) {
            log("Error for session: " + request.getSession(true).getId());
            event.close();
        } else if (event.getEventType() == CometEvent.EventType.END) {
            log("End for session: " + request.getSession(true).getId());
            event.close();
        } else if (event.getEventType() == CometEvent.EventType.READ) {
            throw new UnsupportedOperationException("This servlet does not accept data");
        }

    }
}

该Servlet实现CometProcessor后,就可以处理Comet请求了,在event事件中,根据请求状态交给Handler进行处理。定义CometHandler类如下:

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletResponse;

public class CometHandler {
    private ServletResponse response;

    public CometHandler(ServletResponse response){
        this.response = response;
    }


    public void process(){
        System.out.println("休眠6秒,然后返回响应数据");
        try {
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        //写入数据
        try {
            PrintWriter writer = response.getWriter();
            System.out.println("write response info :hello coment");
            writer.println("<h1>Beijing</h1><p>Sunny</p>");
            writer.flush();
            writer.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

处理器休眠几秒后发送数据给客户端。

web.xml配置

在web.xml中配置上述Servlet信息如下:

<servlet>
        <servlet-name>cometServlet</servlet-name>
        <servlet-class>com.CometServlet</servlet-class> 
        <!-- Change the above to use the other servlets -->
    </servlet>
    <servlet-mapping>
        <servlet-name>cometServlet</servlet-name>
        <url-pattern>/cometTest</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
        </welcome-file-list>

客户端

在项目的WebContent目录下创建index.jsp文件,内容如下:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Comet Test</title>
        <SCRIPT TYPE="text/javascript">
            function go(){
                var url = "http://localhost/my_comet/cometTest"
                var request =  new XMLHttpRequest();
                request.open("GET", url, true);
                request.setRequestHeader("Content-Type","application/x-javascript;");
                request.onreadystatechange = function() {
                    if (request.readyState == 4) {
                        if (request.status == 200){
                            console.log("Receive response data."+request.responseText);
                            if (request.responseText) {
                                document.getElementById("cometTest").innerHTML = request.responseText;
                            }
                        }
                        go();
                    }
                };
                request.send(null);
            }
        </SCRIPT>
    </head>
    <body>
        <h1>Rapid Fire Weather</h1>
        <input type="button" onclick="go()" value="Go!"></input>
        <div id="cometTest"></div>
    </body>
</html>

客户端使用ajax轮询,一旦服务器端返回数据,立即进行下一轮循环,如果没有数据就阻塞等待。

程序启动

Comet只有在NIO模式下才能启动,所以需要修改server.xml配置设置connetor为NIO模式:

<Connector URIEncoding="UTF-8" maxThreads="150" port="80" 
protocol="org.apache.coyote.http11.Http11NioProtocol" 
useBodyEncodingForURI="true"/>

发布项目并运行,页面点击“Go”按钮,浏览器就开始进行轮询请求。

参考链接

参考下列链接,然后自定义CometHander处理请求,完成数据发送流程的。
https://www.ibm.com/developerworks/cn/web/wa-cometjava/

启示录

Tomcat8.5是不是废弃了Comet呢?客户端和服务器端全双工的通讯模式的技术还有websocket,tomcat8.5废弃Comet,大概是因为它支持websocket了,而这两种技术其实是一样的功能。

对于Comet,之所以想了解它,是因为我已经实践并应用过websocket了,对比了下它们能提供的功能,差异不大。而websocket似乎更普及一些,可能Comet的大势已去了吧。

Comet4J(Comet for Java)是一个纯粹基于AJAX(XMLHTTPRequest)的服务器推送框架,消息以JSON方式传递,具备长轮询、长连接、自动选择三种工作模式。 功能特性 推送消息广播。 推送定向消息。 提供连接上线前、上线、下线前、下线、发送消息等多种可处理事件。 消息缓存机制,确保长轮询工作模式下不丢失消息。 客户端正常下线,服务端可立即感知。 客户端异常停止工作,服务端可定时检查并感知。 以注册通道应用的方式,让开发者对框架功能进行扩展,实现自己的应用。 框架特性 独立小巧,不依赖于第三方包。 与应用紧密集成,无需独立应用或服务器。 与Session无关的连接机制,为开发人员提供最大程度的功能可控性。 面向事件编程,客户端与服务器端均为事件驱动开发模式,提供了良好的可扩展性机制。 各项性能参数均可配置。 支持多种主流浏览器,并支持Air应用环境。 服务器支持情况 Tomcat6、Tomcat7 浏览器支持情况 支持XMLHTTPRequest对象的浏览器均可支持长轮询工作模式,但不一定能够支持长连接。 | 浏览器/平台 | 版本 | 长轮询 | 长连接 | |:-----------|:-------|:--------|:--------| | Internet Explorer | 6,7,8,9 | √ | X | | FireFox | 3.0+(更底版本未知) | √ | √ | | Chrome | 7.0+(更底版本未知) | √ | √ | | Safari | 5+(更底版本未知) | √ | √ | | Opera | 11.10+(更底版本未知) | √ | X | | Air | 1.5+(更底版本未知) | √ | √ | | IOS(Iphone/Ipad)| 3.1+(更底版本未知) | √ | √ | | Android | 未测试 | 未知 | 未知 | | BlackBerry | 未测试 | 未知 | 未知 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值