如何在Tomcat7上关闭CometProcessor中的连接?

时间:2012-02-07 20:06:24

标签: java comet tomcat7

我正在编写一个用于提供AJAX事件的长轮询服务。为此,我使用的是Tomcat7 CometProcessor servlet。 servlet类似于Tomcat聊天servlet示例。

对于每个传入请求,都会使用ConnectionCometEventHttpServletRequest和一些请求参数创建HttpServletResponse对象。该请求按userId存储在多个地图中,即每个userId可能有一个或多个打开的请求/连接。

AJAX事件通过一个单独的线程发送,只要用户的新数据到达就会触发该线程。 SenderThread获取事件列表,此用户的打开连接列表,并将事件发送到每个连接。

现在问题是:当数据在SenderThread中发送时,我想关闭连接。我该怎么做?我是否需要在发件人主题中致电event.close(),我应关闭OutputStream还是设置Connection: close标题?

我尝试了各种各样的东西,但似乎都没有正常工作,文档相当薄。

下面的代码只是说明代码的样子,因为实际代码太长了。所以不要看错误检查或竞争条件。

public class AjaxServlet extends HttpServlet implements CometProcessor {
    ConcurrentMultiMap connections = new ConcurrentMultiMap();
    SenderThread senderThread = new SenderThread();

    public void event(CometEvent event) {
        HttpServletRequest req = event.getHttpServletRequest();
        HttpServletResponse res = event.getHttpServletResponse();

        // error checking omitted
        String userId = req.getParameter("userId");
        Long lastId = Long.parseLong(req.getParameter("lastId"));
        Long requestId = req.getAttribute("requestId");

        switch(event.getEventType()) {      
            case BEGIN:
                event.setTimeout(30000L);
                req.setAttribute("requestId", requestId.incrementAndGet());
                addConnection(userId, requestId, lastId, event);
                break;

            case END:
                removeConnection(userId, requestId);
                event.close();
                break;

            case ERROR:
                boolean timeout = event.getSubType().equals(TIMEOUT);
                if (timeout)
                    res.setStatus(408);
                event.close();
                break;
        }
    }

    public void addConnection(...) {
        // add new connection to connections
    }

    public void removeConnection(long userId, long requestId) {
        // remove connection from connections
    }

    public void init() {
        Thread t = new Thread(senderThread);
        t.setDaemon(true);
        t.start();
    }


    class Connection {
        CometEvent event;       
        long requestId;
        long lastId;

        Connection(CometEvent event, long requestId, long lastId) {
            // details omitted
        }
    }

    class SenderThread implements Runnable {
        private boolean running = true;
        private BlockingQueue<Long> queue = new LinkedBlockingQueue<Long>();

        public void stop() {
            running = false;
        }

        public void pushToUser(long userId) {
            queue.add(userId);
        }

        public void run() {
            while (running) {
                try {
                    long userId = queue.take(); // block until 
                    List<Event> events = eventService.forUser(userId);
                    if (!events.isEmpty()) {
                        List<Connection> conn = connections.get(userId);
                        for (Connection c:connections.get(userId)) {
                            sendEvents(events);
                            // HOW DO I CLOSE THE CONNECTION HERE?
                            // removeConnection(userId, c.requestId);
                            // c.event.close();
                        }                   
                    }

                } catch(Exception e) {
                    // error checking omitted
                }
            }
        }

        private void sendEvents(List<Event> events) {
            String json = ... 
            byte[] data = json.getBytes("UTF-8");
            response.setStatus(200);
            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            response.setContentLength(data.length);
            OutputStream os = response.getOutputStream();
            os.write(b);
            os.flush();
            os.close(); // WILL THIS CLOSE THE CONNECTION?
        }
    }
}

0 个答案:

没有答案
相关问题