【问题标题】:How to implement a chat server using HTTP Keepalive headers如何使用 HTTP Keepalive 标头实现聊天服务器
【发布时间】:2011-06-20 10:39:37
【问题描述】:

我想知道如何实现一个“推送”聊天服务器,它使用 HTTP keepalive 标头。我刚开始了解聊天服务器使用的两种技术 - 长轮询和推送 - 但我无法了解幕后发生的事情。

谁能帮帮我?任何客户端/服务器端代码都将不胜感激!

【问题讨论】:

    标签: http push long-polling


    【解决方案1】:

    这是 Tomcat 文档 (hhttp://tomcat.apache.org/tomcat-7.0-doc/aio.html) 中的一些彗星代码

    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);
                        }
                    }
                }
    
            }
    
        }
    
    }
    

    }

    【讨论】:

    【解决方案2】:

    有许多特定的技术,现在通常以Comet 的名称为人所知。那里链接的维基百科文章有一个很好的介绍。

    另见The Long Polling Technique

    【讨论】:

    • 谢谢拉夫。 Wiki 说“长轮询也称为 Comet 编程”...我特别想了解“HTTP 服务器推送”——我可以在我的程序中实现而不使用大量 API。
    猜你喜欢
    • 1970-01-01
    • 2014-06-08
    • 2014-11-13
    • 2011-08-28
    • 2010-10-28
    • 2012-10-17
    • 1970-01-01
    • 1970-01-01
    • 2014-04-17
    相关资源
    最近更新 更多