2011-02-03 64 views
0

我想知道如何实现使用HTTP keepalive标头的“推送”聊天服务器。我刚刚开始了解聊天服务器使用的两种技术 - 长时间轮询和推送 - 但我无法获得关于幕后发生的事情的任何概念。如何使用HTTP Keepalive标头实现聊天服务器

任何人都可以帮我吗?任何客户端/服务器端代码将不胜感激!

回答

0

这里是从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); 
        } 
       } 
      } 

     } 

    } 

} 

}

+0

谢谢Karthik!你能给我看一些客户端代码吗? – SlowAndSteady 2011-02-03 05:58:12

0

有许多特定的技术,通常现在已知的名称为Comet。维基百科的文章链接了一个相当不错的介绍。

另请参阅The Long Polling Technique

+0

由于拉夫。维基说,“长轮询也被称为彗星编程”......我特别想知道“HTTP服务器推送” - 我可以在我的程序中实现而不使用大量API。 – SlowAndSteady 2011-02-03 05:53:17