清单1. 修改Tomcat 的server.xml
coyote.http11.Http11NioProtocol" redirectPort="8443"/> Servlet。这显然是Tomcat 特有的一个接口。清单2 显示了一个这样的例子。 清单2. Tomcat Comet servlet public class TomcatWeatherServlet extends HttpServlet implements CometProcessor { private MessageSender messageSender = null; private static final Integer TIMEOUT = 60 * 1000; @Override public void destroy() { messageSender.stop(); messageSender = null; } @Override public void init() throws ServletException { messageSender = new MessageSender(); Thread messageSenderThread = new Thread(messageSender, "MessageSender[" + getServletContext() .getContextPath() + "]"); messageSenderThread.setDaemon(true); messageSenderThread.start(); } public void event(final 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()); messageSender.setConnection(response); Weatherman weatherman = new Weatherman(95118, 32408); new Thread(weatherman).start(); } 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"); } } } CometProcessor 接口要求实现event 方法。这是用于Comet 交互的一个生命周期方法。Tomcat 将使用不同的CometEvent 实例调用。通过检查CometEvent 的eventType,可以判断正处在生命周期的哪个阶段。当请求第一次传入时,即发生BEGIN 事件。READ 事件表明数据正在被发送,只有当请求为POST 时才需要该事件。遇到END 或ERROR 事件时,请求终止。 在清单2 的例子中,Servlet 使用一个MessageSender 类发送数据。这个类的实例是在servlet 的init 方法中在其自身的线程中创建,并在servlet 的destroy 方法中销毁的。清单3 显示了MessageSender。 清单3. MessageSender private class MessageSender implements Runnable { protected boolean running = true; protected final ArrayList messages = new ArrayList(); private ServletResponse connection; private synchronized void setConnection(ServletResponse connection){ this.connection = connection; notify(); } public void send(String message) { synchronized (messages) { messages.add(message); log("Message added #messages=" + messages.size()); messages.notify(); } } public void run() { while (running) { if (messages.size() == 0) { try { synchronized (messages) { messages.wait(); } } catch (InterruptedException e) { // Ignore } } String[] pendingMessages = null; synchronized (messages) { pendingMessages = messages.toArray(new String[0]); messages.clear(); } try { if (connection == null){ try{ synchronized(this){ wait(); } } catch (InterruptedException e){ // Ignore } } PrintWriter writer = connection.getWriter(); for (int j = 0; j < pendingMessages.length; j++) { final String forecast = pendingMessages[j] + " "; writer.println(forecast); log("Writing:" + forecast); } writer.flush(); writer.close(); connection = null; log("Closing connection"); } catch (IOException e) { log("IOExeption sending message", e); }