java 实现长链接Comet
测试环境Tomcat7
Servlet3以后才支持异步Servlet, Tomcat7中才支持. 其他jsp服务器没有测试.
1. Servlet
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import java.io.IOException; 2 import java.util.Enumeration; 3 import java.util.UUID; 4 5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 10 import net.sf.json.JSONObject; 11 12 13 14 15 public class CometServlet extends HttpServlet { 16 17 @Override 18 protected void doGet(HttpServletRequest req, HttpServletResponse resp) 19 throws ServletException, IOException { 20 doPost(req, resp); 21 } 22 23 @Override 24 protected void doPost(HttpServletRequest req, HttpServletResponse resp) 25 throws ServletException, IOException { 26 System.out.println("CometServlet" + req); 27 Object UserId = req.getSession().getAttribute("UserId"); 28 if (UserId == null) { 29 UserId = UUID.randomUUID().toString(); 30 req.getSession().setAttribute("UserId", UserId); 31 } 32 System.out.println("Userid=" + UserId); 33 if (!req.isAsyncStarted()) { 34 req.startAsync(); 35 } 36 resp.addHeader("Connection", "keep-alive"); 37 resp.addHeader("Content-Type", "text/html; charset=utf-8"); 38 Enumeration<String> names = req.getParameterNames(); 39 40 JSONObject json = new JSONObject(); 41 String key; 42 while (names.hasMoreElements()) { 43 key = names.nextElement(); 44 json.put(key, req.getParameter(key)); 45 } 46 AsynResult asynResult = new AsynResult(req.getAsyncContext(), json, 47 UserId.toString()); 48 AsynMsg.getInstance().AddClient(asynResult); 49 } 50 }
2. 同步消息缓存
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import javax.servlet.AsyncContext; 2 import javax.servlet.ServletResponse; 3 4 import net.sf.json.JSONObject; 5 6 public class AsynResult { 7 private AsyncContext context; 8 private JSONObject json; 9 private String userId; 10 11 public AsyncContext getContext() { 12 return context; 13 } 14 15 public JSONObject getJson() { 16 return json; 17 } 18 19 public String getUserId() { 20 return userId; 21 } 22 23 public AsynResult(AsyncContext context, JSONObject json, String userId) { 24 this.context = context; 25 this.json = json; 26 this.userId = userId; 27 } 28 29 public void send(JSONObject json) { 30 try { 31 ServletResponse rep = context.getResponse(); 32 rep.setContentType("application/json;charset=UTF-8"); 33 rep.setCharacterEncoding("UTF-8"); 34 rep.getWriter().write(json.toString()); 35 } catch (Exception e) { 36 } 37 } 38 }
3. 消息处理
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import java.util.HashMap; 2 import java.util.Map; 3 4 import net.sf.json.JSONObject; 5 6 7 8 public class AsynMsg { 9 // List<AsynResult> clients = new ArrayList<AsynResult>(); 10 private Map<String, AsynResult> clients = new HashMap<String, AsynResult>(); 11 // region 实现该类的单例 12 private static final AsynMsg _Instance = new AsynMsg(); 13 private static final String KEY = "msg"; 14 15 private AsynMsg() { 16 } 17 18 public static AsynMsg getInstance() { 19 return _Instance; 20 } 21 22 public void AddClient(AsynResult result) { 23 String type = result.getJson().optString("type", "data"); 24 String to = result.getJson().optString("to", null); 25 String user = result.getUserId(); 26 String from = user; 27 28 if (type.equals("wait")) { 29 if("lott".equals(result.getJson().optString("msgType",""))){ 30 user = "lott"; 31 } 32 clients.put(user, result); 33 try { 34 synchronized (clients) { 35 clients.wait(); 36 } 37 } catch (InterruptedException e) { 38 e.printStackTrace(); 39 } 40 } else { 41 if("".equals(type)){ 42 to = "lott"; 43 } 44 JSONObject json = new JSONObject(); 45 json.put(KEY, user + ":" + result.getJson().getString("asynMsg")); 46 // 将当前请求的内容输出到客户端 47 result.send(json); 48 49 // 否则将遍历所有已缓存的client,并将当前内容输出到客户端 50 sendMsg(user + ":" + result.getJson().getString("asynMsg"), from, 51 to,type); 52 } 53 54 } 55 56 public void sendMsg(String content) { 57 sendMsg(content, "系统", null, "data"); 58 } 59 60 // / <summary> 61 // / 遍歷所有客戶端, 將消息傳送給客戶端 62 // / </summary> 63 // / <param name="orderType"></param> 64 public void sendMsg(String content, String from, String to, String type) { 65 synchronized (clients) { 66 clients.notifyAll(); 67 } 68 JSONObject json = new JSONObject(); 69 json.put(KEY, content); 70 json.put("from", from); 71 json.put("to", to); 72 json.put("type", type); 73 System.out.println(json); 74 if (to == null || to.toUpperCase().equals("ALL")) { 75 for (AsynResult value : clients.values()) { 76 value.send(json); 77 value.getContext().complete(); 78 } 79 // 清空所有缓存 80 clients.clear(); 81 } else { 82 AsynResult value = clients.get(to); 83 value.send(json); 84 System.out.println(value.getContext().getRequest().isAsyncStarted()); 85 if(value.getContext().getRequest().isAsyncStarted()){ 86 value.getContext().complete(); 87 } 88 } 89 } 90 }
4. 通过jsp建立长链接
http://localhost:8080/Comet/CometServlet?content=&type=wait
5. 通过jsp响应长链接
http://localhost:8080/Comet/json/home!SendMsg.do
6. 通过java程式模拟http建立长链接
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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响应长链接
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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", "恭喜您中奖了."); } }