java comet 长轮询的案例

  这个案例主要是java的comet 长轮询功能的实现,看到网上的案例只是从后台推送消息到前端,而且很多都是(iframe, 流的方式),
很难找到从客户端发送消息到服务器端,服务器端接收到消息之后推送到前端,这中间涉及到Event事件处理顺序在不同的浏览器(IE,FF, Chorme)也不同。

  PS:主要说的就是是IE。以下内容是经过我测试发现的,如果有说的不对的,可以提出交流。

  * 对于http://bbs.csdn.net/topics/391951969的问题,是由于tomcat6.x在解析post请求参数的时候出现了异常(算是bug),换成7.x就可以了。

 public void event(CometEvent evt) {
        try {
            //对于event而言,会存在多个状态,
            if(evt.getEventType() == CometEvent.EventType.BEGIN) {
              //请求开始触发(所有浏览器一致)
            } else if(evt.getEventType() == CometEvent.EventType.END) {
              //请求完成后触发(IE:是在下个请求开始前触发,Chrome是在请求之后触发,FF应该和Chrome是一致的)
              /****这是最大的区别,这个花费了我好长时间测试,本来想在CSND上求救(http://bbs.csdn.net/topics/391951969),居然两天每人回,调试了老半天,问题终于被我发现了。唉不容易啊。****/
            } else if(evt.getEventType() == CometEvent.EventType.ERROR) {
              //请求出现错误触发
            } else if(evt.getEventType() == CometEvent.EventType.READ) {
              //请求读的时候触发
            }
        } catch(IOException e) {
            e.printStackTrace();
        }
}


说了那么多贴上源码:

类:MessageServlet 建立长连接

内部类 : RandomThread 产生消息

package com.comet.servlet;

import java.io.IOException;
import java.util.Random;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.CometEvent;
import org.apache.catalina.CometProcessor;

/**
 * Servlet implementation class SecondServlet
 */
public class MessageServlet extends HttpServlet implements CometProcessor {
    private static final long serialVersionUID = 1L;
    private MessageSender msgSender = MessageSender.getInstance();

    /**
     * @see CometProcessor#event(CometEvent)
     */
    public void event(CometEvent evt) {
        /**
         * evt 方法用来处理各种请求,可以根据状态的不同得到各种响应
         * 同时可以不断根据自己的需求向客户端发送信息
         */
        HttpServletResponse response = evt.getHttpServletResponse();
        HttpServletRequest request = evt.getHttpServletRequest();
        try {
            String sessionId = request.getSession().getId();
            //对于event而言,会存在多个状态,
            if(evt.getEventType() == CometEvent.EventType.BEGIN) {
                //在begin的时候操作
                System.out.println(response + "正在建立连接.");
                msgSender.setConn(sessionId, response);
            } else if(evt.getEventType() == CometEvent.EventType.END) {
                //在结束的时候
                System.out.println(response + "已经结束.");
                msgSender.remove(sessionId, response);
                evt.close();
            } else if(evt.getEventType() == CometEvent.EventType.ERROR) {
                //在发送错误的时候
                System.out.println(response + "发生错误.");
                msgSender.remove(sessionId, response);
                evt.close();
            } else if(evt.getEventType() == CometEvent.EventType.READ) {
                //还在读取数据的状态
                throw new RuntimeException("该状态无法操作");
            }
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * @see Servlet#init(ServletConfig)
     */
    public void init(ServletConfig config) throws ServletException {
        Thread msgThread = new Thread(msgSender);
        msgThread.setDaemon(true);//后台进程
        msgThread.start();
        
        RandomThread rr = new RandomThread();
        Thread rt = new Thread(rr);
        rt.start();
        super.init();
    }

    @Override
    public void destroy() {
        msgSender.close();
        super.destroy();
    }
}


class RandomThread implements Runnable {
    
    private final static Random ran = new Random(10);
    private boolean running = true;
    private MessageSender msgSender = MessageSender.getInstance();
    
    @Override
    public void run() {
        try {
            while(running) {
                Thread.sleep(4000);
                int num = ran.nextInt(10);
System.out.println("产生消息:"+num);
                msgSender.sendMsg(num + "");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


类:MessageSender 发送消息

package com.comet.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletResponse;

/**
 * 消息发送类
 * @author xingyakai
 *
 */
public class MessageSender implements Runnable {
    
    private String msg = new String();
    Map> conns = new HashMap>();
    public boolean running = true;
    
    private static MessageSender messageSender = new MessageSender();
    
    private MessageSender() {}
    
    public static MessageSender getInstance() {
        return messageSender;
    }
    
    public void close() {
        running = false;
    }
    
    public synchronized void sendMsg(String msg) {
        this.msg = msg;
        this.notify();
    }
    
    public void remove(String sessionId, HttpServletResponse response) {
        synchronized (this.conns) {
            conns.get(sessionId).remove(response);
        }
    }
    
    public void setConn(String sessionId, HttpServletResponse conn) {
        synchronized (this.conns) {
            List _responses = this.conns.get(sessionId);
            if(_responses == null) {
                _responses = new ArrayList();
            }
            _responses.add(conn);
            conns.put(sessionId, _responses);
        }
    }
    
    public List getAllResponse() {
        List _allResponses = new ArrayList();
        Set _sessionIds = conns.keySet();
        for(String sessionId : _sessionIds) {
            _allResponses.addAll(conns.get(sessionId));
        }
        return _allResponses;
    }
    
    @Override
    public void run() {
        try {
            while(running) {
                String msg = "";
                if(this.msg == null || this.msg == "") {
                    synchronized (this) {
                        this.wait();
                    }
                }
                msg = this.msg;
                this.msg = null;
                synchronized (this.conns) {
                    List responses = this.getAllResponse();
                    for(HttpServletResponse response : responses) {
                        response.setContentType("text/html");
                        PrintWriter    out = response.getWriter();
                        System.out.println("发送消息:" + msg);
                        out.print(msg);
                        out.flush();
                        out.close();
                        out = null;
                    }
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

前端页面:index.html







Comet



前端页面:sendMsg.jsp

<%@page import="com.comet.servlet.MessageSender"%>

<%
    MessageSender sender = MessageSender.getInstance();
    sender.sendMsg("Test");
%>

web.xml



  MComet
  
    index.html
  
   
    
    MessageServlet
    MessageServlet
    com.comet.servlet.MessageServlet
  
  
    MessageServlet
    /MessageServlet.htm
  


server..xml

 
 

你可能感兴趣的:(java comet 长轮询的案例)