如何使用HTTP Keepalive头实现聊天服务器

如何使用HTTP Keepalive头实现聊天服务器,http,push,long-polling,Http,Push,Long Polling,我想知道如何实现一个使用HTTP keepalive头的“推送”聊天服务器。我刚刚了解了聊天服务器使用的两种技术——长轮询和推送——但我对幕后发生的事情没有任何概念 有人能帮我吗?任何客户端/服务器端代码都将不胜感激 有许多特定的技术,现在通常以这个名字命名。维基百科链接的文章有一个很好的介绍 另请参见。这里是来自Tomcat文档的一些comet代码(hhttp://tomcat.apache.org/tomcat-7.0-doc/aio.html) 公共类聊天servlet 扩展HttpSer

我想知道如何实现一个使用HTTP keepalive头的“推送”聊天服务器。我刚刚了解了聊天服务器使用的两种技术——长轮询和推送——但我对幕后发生的事情没有任何概念


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

有许多特定的技术,现在通常以这个名字命名。维基百科链接的文章有一个很好的介绍


另请参见。

这里是来自Tomcat文档的一些comet代码(hhttp://tomcat.apache.org/tomcat-7.0-doc/aio.html)

公共类聊天servlet
扩展HttpServlet实现CometProcessor{
受保护的ArrayList连接=
新的ArrayList();
受保护的MessageSender=null;
public void init()引发ServletException{
messageSender=新建messageSender();
Thread messageSenderThread=
新线程(messageSender,“messageSender[“+getServletContext().getContextPath()+”]);
messageSenderThread.setDaemon(true);
messageSenderThread.start();
}
公共空间销毁(){
连接。清除();
messageSender.stop();
messageSender=null;
}
/**
*处理给定的Comet事件。
* 
*@param event将要处理的Comet事件
*@抛出异常
*@ServletException
*/
公共无效事件(CometEvent)
抛出IOException、ServletException{
HttpServletRequest=event.getHttpServletRequest();
HttpServletResponse=event.getHttpServletResponse();
if(event.getEventType()==CometEvent.EventType.BEGIN){
日志(“开始会话:+request.getSession(true.getId());
PrintWriter=response.getWriter();
writer.println(“”);
println(“JSP聊天”);
writer.flush();
已同步(连接){
连接。添加(响应);
}
}else if(event.getEventType()==CometEvent.EventType.ERROR){
日志(“会话错误:+request.getSession(true.getId());
已同步(连接){
连接。移除(响应);
}
event.close();
}else if(event.getEventType()==CometEvent.EventType.END){
日志(“会话结束:+request.getSession(true.getId());
已同步(连接){
连接。移除(响应);
}
PrintWriter=response.getWriter();
writer.println(“”);
event.close();
}else if(event.getEventType()==CometEvent.EventType.READ){
InputStream=request.getInputStream();
字节[]buf=新字节[512];
做{
int n=is.read(buf);//可以引发IOException
如果(n>0){
日志(“读取”+n+”字节:“+新字符串(buf,0,n)
+对于会话:“+request.getSession(true.getId());
}else if(n<0){
错误(事件、请求、响应);
回来
}
}而(is.available()>0);
}
}
公共类MessageSender实现可运行{
受保护的布尔运行=真;
受保护的ArrayList消息=新建ArrayList();
公共消息发送者(){
}
公共停车场(){
运行=错误;
}
/**
*添加用于发送的消息。
*/
公共无效发送(字符串用户、字符串消息){
已同步(消息){
消息。添加(“[”+用户+”]:“+消息);
messages.notify();
}
}
公开募捐{
(跑步时){
if(messages.size()==0){
试一试{
已同步(消息){
messages.wait();
}
}捕捉(中断异常e){
//忽略
}
}
已同步(连接){
字符串[]pendingMessages=null;
已同步(消息){
pendingMessages=messages.toArray(新字符串[0]);
messages.clear();
}
//在所有打开的连接上发送任何挂起的消息
对于(int i=0;i”);
}
writer.flush();
}捕获(IOE异常){
日志(“IOExeption发送消息”,e);
}
}
}
}
}
}

}

谢谢。Wiki说“长轮询也被称为Comet编程”…我特别想知道“HTTP服务器推送”—我可以在我的程序中实现它,而不用使用很多API。谢谢Karthik!你能给我看一些客户端代码吗?看看这里:。更具体地说,这里有很多代码。应该足够让你开始了。但请注意,这件事相当复杂。
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);
                    }
                }
            }

        }

    }

}