java 实现长链接Comet

测试环境Tomcat7

Servlet3以后才支持异步Servlet, Tomcat7中才支持. 其他jsp服务器没有测试.

1. Servlet

import java.io.IOException;
 import java.util.Enumeration;
 import java.util.UUID;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import net.sf.json.JSONObject;
 

 public class CometServlet extends HttpServlet {
 
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp)
             throws ServletException, IOException {
         doPost(req, resp);
     }
 
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp)
             throws ServletException, IOException {
         System.out.println("CometServlet" + req);
         Object UserId = req.getSession().getAttribute("UserId");
         if (UserId == null) {
             UserId = UUID.randomUUID().toString();
             req.getSession().setAttribute("UserId", UserId);
         }
         System.out.println("Userid=" + UserId);
         if (!req.isAsyncStarted()) {
             req.startAsync();
         }
         resp.addHeader("Connection", "keep-alive");
         resp.addHeader("Content-Type", "text/html; charset=utf-8");
         Enumeration<String> names = req.getParameterNames();
 
         JSONObject json = new JSONObject();
         String key;
         while (names.hasMoreElements()) {
             key = names.nextElement();
             json.put(key, req.getParameter(key));
         }
         AsynResult asynResult = new AsynResult(req.getAsyncContext(), json,
                 UserId.toString());
         AsynMsg.getInstance().AddClient(asynResult);
     }
 }

2. 同步消息缓存

import javax.servlet.AsyncContext;
import javax.servlet.ServletResponse;

import net.sf.json.JSONObject;

public class AsynResult {
    private AsyncContext context;
    private JSONObject json;
    private String userId;

    public AsyncContext getContext() {
        return context;
    }

    public JSONObject getJson() {
        return json;
    }

    public String getUserId() {
        return userId;
    }

    public AsynResult(AsyncContext context, JSONObject json, String userId) {
        this.context = context;
        this.json = json;
        this.userId = userId;
    }

    public void send(JSONObject json) {
        try {
            ServletResponse rep = context.getResponse();
            rep.setContentType("application/json;charset=UTF-8");
            rep.setCharacterEncoding("UTF-8");
            rep.getWriter().write(json.toString());
        } catch (Exception e) {
        }
    }
}

3. 消息处理

import java.util.HashMap;
import java.util.Map;

import net.sf.json.JSONObject;

 
public class AsynMsg {
    // List<AsynResult> clients = new ArrayList<AsynResult>();
    private Map<String, AsynResult> clients = new HashMap<String, AsynResult>();
    // region 实现该类的单例
    private static final AsynMsg _Instance = new AsynMsg();
    private static final String KEY = "msg";

    private AsynMsg() {
    }

    public static AsynMsg getInstance() {
        return _Instance;
    }

    public void AddClient(AsynResult result) {
        String type = result.getJson().optString("type", "data");
        String to = result.getJson().optString("to", null);
        String user = result.getUserId();
        String from = user;

        if (type.equals("wait")) {
            if("lott".equals(result.getJson().optString("msgType",""))){
                user = "lott";
            }
            clients.put(user, result);
            try {
                synchronized (clients) {
                    clients.wait();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            if("".equals(type)){
                to = "lott";
            }
            JSONObject json = new JSONObject();
            json.put(KEY, user + ":" + result.getJson().getString("asynMsg"));
            // 将当前请求的内容输出到客户端
            result.send(json);

            // 否则将遍历所有已缓存的client,并将当前内容输出到客户端
            sendMsg(user + ":" + result.getJson().getString("asynMsg"), from,
                    to,type);
        }

    }

    public void sendMsg(String content) {
        sendMsg(content, "系统", null, "data");
    }

    // / <summary>
    // / 遍歷所有客戶端, 將消息傳送給客戶端
    // / </summary>
    // / <param name="orderType"></param>
    public void sendMsg(String content, String from, String to, String type) {
        synchronized (clients) {
            clients.notifyAll();
        }
        JSONObject json = new JSONObject();
        json.put(KEY, content);
        json.put("from", from);
        json.put("to", to);
        json.put("type", type);
        System.out.println(json);
        if (to == null || to.toUpperCase().equals("ALL")) {
            for (AsynResult value : clients.values()) {
                value.send(json);
                value.getContext().complete();
            }
            // 清空所有缓存
            clients.clear();
        } else {
            AsynResult value = clients.get(to);
            value.send(json);
            System.out.println(value.getContext().getRequest().isAsyncStarted());
            if(value.getContext().getRequest().isAsyncStarted()){
            value.getContext().complete();
            }
        }
    }
}

4. 通过jsp建立长链接

http://localhost:8080/Comet/CometServlet?content=&type=wait

5. 通过jsp响应长链接

http://localhost:8080/Comet/json/home!SendMsg.do

6. 通过java程式模拟http建立长链接

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.ResourceBundle;

import net.sf.json.JSONObject;

public class HttpCometUtils {
    // private static String host = "http://localhost:8080/Comet/";
    private static String action = "json/home!SendMsg.do?msgType=ALL";
    protected static ResourceBundle projectBundle = ResourceBundle
            .getBundle("DataBaseServer");
    public static Thread CometThread = null;
    private static String host = projectBundle.getString("web_server");
    public static boolean isLogin = false;
    static {
        if (!host.endsWith("/")) {
            host += "/";
        }
    }

    public HttpCometUtils() {
        // host = "http://localhost:8080/Comet/";
        if (!host.endsWith("/")) {
            host += "/";
        }
    }

    /**
     * @param urlString
     * @param method
     * @param type
     * @param msg
     * @throws IOException
     */
    public static void connectServer() {
        new Thread() {
            @Override
            public void run() {
                int errorCount = 0;
                while (isLogin) {
                    if (errorCount >= 10) {
                        try {
                            Thread.sleep(15000);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                            break;
                        }
                    }
                    URL url = null;
                    HttpURLConnection urlConnection = null;
                    try {
                        String serverURL = host
                                + "CometServlet?content=&type=wait&msgType=lott";
                        System.out.println(serverURL);
                        url = new URL(serverURL);

                        urlConnection = (HttpURLConnection) url
                                .openConnection();

                        urlConnection.setRequestMethod("GET");
                        urlConnection.setDoOutput(true);
                        urlConnection.setDoInput(true);
                        urlConnection.setUseCaches(false);
                        InputStream is = urlConnection.getInputStream();
                        byte[] b = new byte[is.available()];
                        is.read(b);
                        String jsmsg = new String(b, "utf-8");
                        System.out.println(jsmsg);
                        if(jsmsg.equals("")){
                            jsmsg = "{}";
                        }
                        JSONObject json = JSONObject.fromObject(jsmsg);
                        Object obj = null;
                        if (json.containsKey("type")) {
                            obj = json.get("type");
                            if (obj != null && "lott".equals(obj)) {
                                json = (JSONObject) json.get("msg");
                                if (json.containsKey("chatMsg")) {                                    
                                    System.out.println(json.get("chatMsg"));
                                }
                            }

                        }

                        errorCount = 0;
                    } catch (MalformedURLException e) {
                        errorCount++;
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IOException e) {
                        errorCount++;
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (Exception e) {
                        errorCount++;
                        e.printStackTrace();
                    } finally {

                        if (urlConnection != null) {
                            urlConnection.disconnect();
                        }
                    }

                }
            }
        }.start();
    }

    public static void main(String[] args) {
        int x = new Random(System.currentTimeMillis()).nextInt(100);
        HttpCometUtils.isLogin = true;
        HttpCometUtils.connectServer();
    }
}

7. 通过java程式模拟http响应长链接

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Random;
import java.util.ResourceBundle;

public class HttpUtils {
    // private static String host = "http://localhost:8080/Comet/";
    private static String action = "json/home!SendMsg.do?msgType=ALL";
    protected static ResourceBundle projectBundle = ResourceBundle
            .getBundle("DataBaseServer");
    private static String host = "http://localhost:8080/Comet";//projectBundle.getString("web_server");
    static {
        if (!host.endsWith("/")) {
            host += "/";
        }
    }

    public HttpUtils() {
        if (!host.endsWith("/")) {
            host += "/";
        }
    }

    /**
     * @param urlString
     * @param method
     * @param type
     * @param msg
     * @throws IOException
     */
    public static void send(final String type, final String asynMsg) {
        new Thread() {
            @Override
            public void run() {


                URL url = null;
                HttpURLConnection urlConnection = null;
                try {
                    StringBuffer param = new StringBuffer();
                    param.append("&type=").append(type);
                    param.append("&asynMsg=").append(URLEncoder.encode(asynMsg, "UTF-8"));
                    String urlString = param.toString();
                    
                    String serverURL = host + action + urlString;
                    System.out.println(serverURL);
                    url = new URL(serverURL);
                    
                    urlConnection = (HttpURLConnection) url.openConnection();

                    urlConnection.setRequestMethod("GET");
                    // urlConnection.setDoOutput(true);
                    // urlConnection.setDoInput(true);
                    urlConnection.setUseCaches(false);

                    System.out.println(urlConnection.getResponseMessage());
                } catch (MalformedURLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (urlConnection != null) {
                        urlConnection.disconnect();
                    }
                }

            }

        }.start();
    }

    public static void main(String[] args) {
        int x = new Random(System.currentTimeMillis()).nextInt(100);
        HttpUtils.send("chat", "恭喜您中奖了.");
    }
}

相关推荐