`
birdmen
  • 浏览: 38504 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

comet之 Tomcat6 的servlet异步处理实现

阅读更多
Comet支持
  Comet支持允许一个servlet异步处理IO,当数据在连接上可读的时候(而不是使用阻塞读)和往连接异步(最有可能的是来自一些其它原引发的事件)写回数据的时候接收事件。

CometEvent
  实现了org.apache.catalina.CometProcessor接口的Sevlets有他们的事件激活方法而不是使用平常的服务方法,依照谁发生的事件。事件对象引发存取通常的request和respose对象,它可能使用平常的方式。重要的区别是这些对象在任何时候保持有效和全功能,在事件BEGIN开始到END或者ERROR事件结束。下面是这些事件类型:

◆ EventType.BEGIN: 在连接处理开始将被调用。它能被用来初始化任何在request和response对象中使用的相关字段。 在这个事件处理之后和结束处理开始或者错误事件之间,是可以使用response对象来在连接上进行异步写。注意,reponse对象和依靠的 OutputStream和Writer仍然不是同步的,因此当多个线程存取的时候,同步是强制的。在初始事件处理之后,request才会提交。
◆ EventType.READ: 这个指示输入数据可以用了,可以无阻塞的读了。可用的和InputStream或者Read的读方法可以用来决定是否有阻塞风险: servlet会读报告可用的数据,还进一步读取可用的数据。当遇到读错误的时候,servlet通过抛出异常来报告它。抛出异常会导致一个错误事件被激活,连接会被关闭。另外,可以捕捉异常,清理sevlet用到的数据结构,然后调用事件的close方法。尝试读取这个方法执行的request对象的数据是不允许的。
  在一些平台上,例如Windows,一个客户端断开会有一个READ事件。从流读数据可能返回-1, IOException 或者 EOFException。确认你处理了所有这三种情况。如果你没有处理,Tomcat会立刻抛出你改捕捉事件,这个时候你会被通知错误。
◆ EventType.END:request 结束时调用。在开始方法中初始化的字段会被重置。在这个事件处理之后,request和response对象, 还有哪些依赖的对象,会被重新使用,用来处理其它的请求。 End在 数据可用和读文件结束的时候也会被调用。
◆ EventType.ERROR: 当容器在连接上遇到IO错误或者类似不可恢复的错误时,这个错误出现。在begin方法初始化的数据会被重置。这个事件处理之后,request和 response对象,还有一些依赖的对象,会被重新被其它请求使用。

这些事事件子类型,允许更详细的事件处理 (注意: 一些事件需要使用org.apache.catalina.valves.CometConnectionManagerValve 值):
◆ EventSubType.TIMEOUT: 连接超时 (ERROR子类型);注意这个错误类型不是致命的,连接不会被关闭除非servlet使用了事件的close方法.
◆ EventSubType.CLIENT_DISCONNECT: 客户端连接被关闭(ERROR子类型).事件的方法.
◆ EventSubType.IOEXCEPTION: 一个IO异常发生, 例如无效内容,一个无效的大块 (ERROR子类型).
◆ EventSubType.WEBAPP_RELOAD: web程序正在被重新加载T(END子类型).
◆ EventSubType.SESSION_END: sevlet结束会话 (END子类型).
   就像上面描述的,典型的Comet请求生命周期将会包含一系列的事件:BEGIN -> READ -> READ -> READ -> ERROR/TIMEOUT. 在任何时候,servlet可以使用事件对象的close方法关闭请求的处理。

CometFilter

类似普通的过滤器,一个过滤器链会被激活当comet事件处理的时候。这些过滤器要应用CometFilter接口(他和平常的过滤器接口一样), 要被声明和影射在部署描述符中,和常规过滤器相同的方式。当处理一个事件的时候,过滤器链仅仅包括哪些匹配所使用影射规则的过滤器,也要实现 CometFiler接口.

例子代码
  下面的伪代码servlet,实现了异步聊天功能,使用上面描述的API:
     public class ChatServlet
            extends HttpServlet implements CometProcessor {

            protected ArrayList<HttpServletResponse> connections =
                new ArrayList<HttpServletResponse>();
            protected MessageSender messageSender = null;
           
            public void init() throws ServletException {
                messageSender = new MessageSender();
                Thread messageSenderThread =
                    new Thread(messageSender, "MessageSender[" + getServletContext().getContextPath() + "]");
                messageSenderThread.setDaemon(true);
                messageSenderThread.start();
            }

            public void destroy() {
                connections.clear();
                messageSender.stop();
                messageSender = null;
            }

            /**
             * Process the given Comet event.
             *
             * @param event The Comet event that will be processed
             * @throws IOException
             * @throws ServletException
             */
            public void event(CometEvent event)
                throws IOException, ServletException {
                HttpServletRequest request = event.getHttpServletRequest();
                HttpServletResponse response = event.getHttpServletResponse();
                if (event.getEventType() == CometEvent.EventType.BEGIN) {
                    log("Begin for session: " + request.getSession(true).getId());
                    PrintWriter writer = response.getWriter();
                    writer.println("<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">");
                    writer.println("<head><title>JSP Chat</title></head><body bgcolor=\"#FFFFFF\">");
                    writer.flush();
                    synchronized(connections) {
                        connections.add(response);
                    }
                } else if (event.getEventType() == CometEvent.EventType.ERROR) {
                    log("Error for session: " + request.getSession(true).getId());
                    synchronized(connections) {
                        connections.remove(response);
                    }
                    event.close();
                } else if (event.getEventType() == CometEvent.EventType.END) {
                    log("End for session: " + request.getSession(true).getId());
                    synchronized(connections) {
                        connections.remove(response);
                    }
                    PrintWriter writer = response.getWriter();
                    writer.println("</body></html>");
                    event.close();
                } else if (event.getEventType() == CometEvent.EventType.READ) {
                    InputStream is = request.getInputStream();
                    byte[] buf = new byte[512];
                    do {
                        int n = is.read(buf); //can throw an IOException
                        if (n > 0) {
                            log("Read " + n + " bytes: " + new String(buf, 0, n)
                                    + " for session: " + request.getSession(true).getId());
                        } else if (n < 0) {
                            error(event, request, response);
                            return;
                        }
                    } while (is.available() > 0);
                }
            }

            public class MessageSender implements Runnable {

                protected boolean running = true;
                protected ArrayList<String> messages = new ArrayList<String>();
               
                public MessageSender() {
                }
               
                public void stop() {
                    running = false;
                }

                /**
                 * Add message for sending.
                 */
                public void send(String user, String message) {
                    synchronized (messages) {
                        messages.add("[" + user + "]: " + message);
                        messages.notify();
                    }
                }

                public void run() {

                    while (running) {

                        if (messages.size() == 0) {
                            try {
                                synchronized (messages) {
                                    messages.wait();
                                }
                            } catch (InterruptedException e) {
                                // Ignore
                            }
                        }

                        synchronized (connections) {
                            String[] pendingMessages = null;
                            synchronized (messages) {
                                pendingMessages = messages.toArray(new String[0]);
                                messages.clear();
                            }
                            // Send any pending message on all the open connections
                            for (int i = 0; i < connections.size(); i++) {
                                try {
                                    PrintWriter writer = connections.get(i).getWriter();
                                    for (int j = 0; j < pendingMessages.length; j++) {
                                        writer.println(pendingMessages[j] + "<br>");
                                    }
                                    writer.flush();
                                } catch (IOException e) {
                                    log("IOExeption sending message", e);
                                }
                            }
                        }

                    }

                }

            }

        }


Comet timeouts
如果你正在使用NIO连接器,你可以设置不同的延时为不同的comet连接。设置一个延时,像下面简单的设置一个属性就可以:
CometEvent event.... event.setTimeout(30*1000);
或者
event.getHttpServletRequest().setAttribute("org.apache.tomcat.comet.timeout", new Integer(30 * 1000));

这里设置延时30秒. 重要提示, 为了设置这个延时, 必须在BEGIN 事件之前设置, 默认值是soTimeout。 如果你正在使用APR连接器, 所有的Comet连接有相同的延时值,是soTimeout*50。

异步写

当 APR或者NIO启用的时候,Tomcat支持发送大的静态文件。这些写操作,系统负载一增加,就在更高效的方式上被异步执行。而不是使用阻塞模式发送大的response,写内容到一个静态文件时可以能的,写它用一个sendfile代码。一个缓存值可以用来缓存response数据到一个文件而不是内存。 Sendfile支持是可用的,如果request属性org.apache.tomcat.sendfile.support被设置成 Boolean.TRUE.
  任何一个Servlet都可以指示Tomcat执行一个sendfile通过设置相应的response属性。当使用Sendfile的时候,最好确认request和response都没被包装,因为response主体将被connector随后发送,他不能被过滤。除了设置3个需要的response属性,servlet不发送任何response数据,但是它可以用来修改response头,例如设置 cookies。

◆ org.apache.tomcat.sendfile.filename: Canonical文件名, String类型
◆ org.apache.tomcat.sendfile.start: Start 偏移量,Long类型
◆ org.apache.tomcat.sendfile.start: End 偏移量,Long类型
     
1
2
分享到:
评论
2 楼 chen_qc 2012-05-15  
弄不懂event方法在什么时候执行,断点跟print都试了
1 楼 romola 2010-05-24  
http://jobsdigg.com/story/3562/ 欢迎投送!!!

相关推荐

    comet4j+tomcat6+tomcat7并附完整版Demo

    【标题】"comet4j+tomcat6+tomcat7并附完整版Demo" 提供的是一种在Java后端与前端之间实现长连接通信的解决方案,主要涉及到的技术包括Comet4j、Tomcat 6和Tomcat 7。Comet技术是用于实现实时Web应用的一种方法,它...

    Tomcat 开发Comet实例

    本文将深入探讨如何在Tomcat中开发一个Comet实例,这是一项用于实现服务器向客户端推送数据的技术,对于实时交互应用如聊天、股票更新或天气预报等场景非常关键。 Comet是一种持久连接技术,它打破了传统的HTTP请求...

    comet4j所需js与jar包(tomcat6与tomcat7)

    标题中的"comet4j所需js与jar包(tomcat6与tomcat7)"表明,这个压缩包包含了Comet4J框架在Tomcat 6和Tomcat 7这两种版本的应用服务器上运行所需的JavaScript文件和Java类库。Tomcat是Apache软件基金会的一个开源...

    Tomcat comet 服务器推技术

    前者基于 Servlet 2.5 的异步处理,后者是针对 Servlet 3.0 引入的,提供更简洁的推送接口。 3. **实现方法**: - **Blocking I/O**:Tomcat 使用的 `org.apache.catalina.connector.OutputBuffer` 类,当输出缓冲...

    comet4j-tomcat7后台信息推送jar包

    Tomcat7是Apache软件基金会的Apache Tomcat服务器的一个版本,它是一个开源的、实现了Java Servlet和JavaServer Pages(JSP)规范的应用服务器。Tomcat7因其轻量级、高效和易于管理的特性,在小型到中型企业级应用中...

    test comet servlet

    总结来说,"test comet servlet"项目旨在探索和实现基于Java Servlet的Comet技术,通过异步通信提高Web应用的实时性能。项目中包含的"comet_test"文件可能涵盖了从服务器端代码到客户端交互的所有组件,以及必要的...

    javaweb实现后台向前台的消息推送 comet4j

    本示例介绍的是如何使用Comet4j这个第三方库来实现后台到前台的消息推送功能。Comet4j是一个专门用于JavaWeb应用的长连接通讯框架,它简化了基于Comet技术的实时通信实现。 首先,我们要理解Comet技术。Comet是一种...

    web推送 comet技术

    配置Tomcat7以支持Comet技术,通常需要修改服务器的配置文件,如`server.xml`,设置`Connector`元素的`asyncTimeout`属性来支持长时间的HTTP连接,并开启异步处理。这允许服务器在处理完一个请求后不立即关闭连接,...

    comet4j.zip完整资源

    总之,Comet4j是一个强大的Web推送框架,通过结合Tomcat6或Tomcat7,可以轻松地实现服务器向客户端的实时数据推送,提升Web应用的用户体验。这个"comet4j.zip完整资源"包含了所有必要的组件,使得开发者能够快速地在...

    Comet4j完整demo

    在Connector标签中添加`asyncSupported="true"`属性,使Tomcat支持异步处理请求,这是实现长连接的基础。 接着,我们需要在项目中引入Comet4j库,并创建一个Comet服务端点。这个服务端点通常是一个Servlet,负责...

    Spring整合DWR comet 实现无刷新 多人聊天室代码整理

    Spring整合DWR(Direct Web Remoting)和Comet技术,是一种高效的实现Web应用程序实时通信的解决方案,特别适用于创建如多人聊天室这样的实时交互应用。在这个项目中,Spring作为后端框架,负责业务逻辑处理和控制...

    Comet Web 应用

    Tomcat通过使用AsyncContext和Servlet 3.0规范中的特性来实现Comet。Servlet 3.0引入了异步处理能力,允许Servlet在请求处理完成后继续运行,这样服务器可以在准备好数据后直接推送给客户端,而无需等待新的请求。...

    servlet.api(中文版)

    6. **AsyncContext和 Comet技术**:Servlet 3.0引入了异步处理能力,通过`AsyncContext`可以在后台线程中执行长时间运行的任务,提高Web应用的响应性。Comet技术是一种长连接技术,通过保持客户端与服务器的连接来...

    气泡提示comet技术

    - Servlet 3.0及以上版本引入了AsyncContext,允许开发者创建异步Servlet,从而支持Comet技术。 - 使用Jetty或Tomcat等服务器的特定扩展,它们提供了对Comet的原生支持。 - 利用WebSocket,这是一种HTML5引入的全...

    tomcat7自用,好用亲测

    1. **Servlet容器**:Tomcat 7 支持Servlet 3.0规范,提供了诸如异步处理、过滤器链增强和注解支持等新特性。这使得开发者能够更方便地配置和管理Servlet。 2. **JSP支持**:它包含了对JSP 2.2的支持,提供了EL...

    Servlet与JSP核心编程第2版

    9. **Servlet API的高级特性**:如Asynchronous Servlet和 Comet技术,用于实现高效的异步通信和长轮询。 10. **JSP自定义标签**:深入介绍了如何创建和使用自定义标签库,以提高代码的可维护性和复用性。 11. **...

    tomcat绿色整合包,包含多个版本

    - Tomcat 7支持Java EE 6规范,引入了WebSocket和Comet支持。 - 版本7.0.79是7.x系列的一个安全更新版本,修复了一些已知的安全漏洞。 - 如果项目依赖Java EE 6特性且需要一定的安全性,7.0.79是较好的选择。 3....

    使用Java实现类似Comet风格的web app

    在开发过程中,你可能需要结合使用多种技术,如使用 AJAX 实现客户端的异步请求,配合服务器端的 Comet 机制来达到实时推送的效果。同时,了解并优化服务器配置,如超时设置、连接池大小等,也是确保应用稳定性和...

    jetty 6 指南书

    14. **异步Servlet,Ajax,Comet**:讲解异步处理和长连接技术。 15. **Embedding Jetty**:如何将Jetty嵌入到应用程序中,实现轻量级部署。 16. **JEE服务器整合**:指导如何与Java EE服务器集成。 17. **开发...

Global site tag (gtag.js) - Google Analytics