`

HTTP 长连接 Comet

    博客分类:
  • java
阅读更多
长连接方式:以前一直局限在http长轮询阻塞、activex控件、flash控件、javaapplet 、websocket 考虑。 最近看到淘宝 增量订单同步的webapi(http://open.taobao.com/doc/detail.htm?id=1029)才有了想法,想进一步了解此http长连接是如何实现,果然别有洞天。
目前此方式主要用于:web实时推送 、web桌面、twitter  、事件驱动(订阅、取消订阅)
 

 COMET   HTTP长连接,实现服务器推(server push),服务以事件(event)方式把消息推送给客户端,来解决客户端定时、频繁访问服务器的问题。

 

comet长连接有两种方式:长轮询方式(long-polling)和流方式(streaming)。

 

长轮询方式:HTTP的连接保持,服务端会阻塞请求,直到服务端有事件触发 OR 超时。客户端在收到相应后,再次发送请求建立连接。 

 

流方式:服务器推送数据给客户端,但是不关闭连接,保持连接,直至超时。超时后客户端关闭连接,同时重新建立连接。Java 通过它的NIO库提供非阻塞IO处理Comet

 

实现:

 

1、支持COMET的服务器有:Tomcat 6.0.14 和Jetty 6.1.14 以后版本。

2、修改Tomcat配置文件conf/server.xml,使支持启动异步版本的IO连接器。

     <Connector connectionTimeout="20000" port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" redirectPort="8443"/>

3、Comet API 此为Tomcat  lib/catalina.jar

4、编写servlet,通过servlet实现 CometProcessor接口中的event() 方法。此方法中分别处理连接开始(BEGIN)、新数据可用(READ),连接结束(END),或出错等事件

 

服务端代码 写道
package com.ist.manage.servlet;

import java.io.IOException;

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;
import org.apache.log4j.Logger;

import com.thread.RandomSender;

public class TestComet extends HttpServlet implements CometProcessor{
private static Logger logger = Logger.getLogger(TestComet.class);
private RandomSender randomSender = null;
private static final Integer TIMEOUT = 60*1000;
public void event(CometEvent event) throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest request = event.getHttpServletRequest();
HttpServletResponse response =event.getHttpServletResponse();
logger.info("Test Comet http长连接测试...");
if(event.getEventType() == CometEvent.EventType.BEGIN){
request.setAttribute("org.apache.tomcat.comet.timeout", TIMEOUT);
//启动线程
 randomSender = new RandomSender(request.getParameter("requestInfo"),response);
Thread thread = new Thread(randomSender);
thread.start();
}else if(event.getEventType() == CometEvent.EventType.READ){
throw new UnsupportedOperationException("this servlet dose not accept data");
}else if(event.getEventType() == CometEvent.EventType.END){
event.close();
}else if(event.getEventType() == CometEvent.EventType.ERROR){
event.close();
}
}

}

 

 

RandomSender 写道
package com.thread;

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

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.log4j.Logger;

import com.sun.org.apache.bcel.internal.generic.NEW;



public class RandomSender implements Runnable {
private static Logger logger = Logger.getLogger(RandomSender.class);
protected boolean running = true;
private ServletResponse response;
private String reqInfo;
Random rand;
String tmpString = "";

public RandomSender(String reqInfo,ServletResponse response){
this.response = response;
this.reqInfo = reqInfo;
logger.info("接收注册请求包信息:"+reqInfo);
rand = new Random();
}
public void run() {
// TODO Auto-generated method stub
PrintWriter out = null;
while (running) {
try {
out = response.getWriter();
logger.info("线程产生随机数..."+Thread.currentThread().getName());
tmpString = "random:"+rand.nextInt(10);
out.println(tmpString);
out.flush();
response.flushBuffer();
Thread.sleep(3000);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (NullPointerException e) {
// TODO: handle exception
e.printStackTrace();
logger.info("客户端关闭,捕获空指针异常");
running = false;
}


}
}

}

 

     客户端代码:采用httpclient4.2.1.jar

package com.http.client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.log4j.Logger;


public class HttpLongClient {
private static Logger logger = Logger.getLogger(HttpClient.class);
	
	/**
	 * 请求返回状态码code 和 结果 result
	 */
	public static Map<String, Object> getHttpByPost(String url,
			String[]... params) {
		Map<String, Object> map = new HashMap<String, Object>();
		org.apache.http.client.HttpClient client = new DefaultHttpClient();
		
//		client.getParams().setIntParameter("http.socket.timeout", 10000);
		
		client.getParams().setParameter("Connection", "Keep-Alive");
		
		HttpPost post = new HttpPost(url);
		List<NameValuePair> nvps = new ArrayList<NameValuePair>();
		StringBuilder builder = new StringBuilder();
		String result = null;
		String responseStr = "";
		int responseCode = 0;
		
		if(params!=null){
			for (String[] param : params) {
			
				nvps.add(new BasicNameValuePair(param[0], param[1]));
			}
		}
		try {
				post.setEntity((HttpEntity) new UrlEncodedFormEntity(nvps, "UTF-8"));
				HttpResponse response = client.execute(post);
				map = doResponse(response);
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ClientProtocolException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		return map;
		
	}
	
	
	
	public static Map<String, Object> getHttpByGet(String url) {
		Map<String, Object> map = new HashMap<String, Object>();
		org.apache.http.client.HttpClient client = new DefaultHttpClient();
	//	client.getParams().setIntParameter("http.socket.timeout", 10000);
		HttpGet get = new HttpGet(url);
		List<NameValuePair> nvps = new ArrayList<NameValuePair>();
		try {
				logger.error("url:"+url);
				HttpResponse response = client.execute(get);
				
				map = doResponse(response);
			} catch (ClientProtocolException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		return map;
		
	}
	
	private static  Map<String, Object> doResponse(HttpResponse response){
		Map<String, Object> map = new HashMap<String, Object>();
		String line = "";
		String result = null;
		String responseStr = "";
		int responseCode = 0;
			try {
			
				HttpEntity entity = response.getEntity();
				BufferedReader reader = new BufferedReader(new InputStreamReader(
						entity.getContent(), "UTF-8"), 8 * 1024);
				StringBuilder builder = new StringBuilder();
				responseCode = response.getStatusLine().getStatusCode();
				
				switch (responseCode) {
				// 请求成功
				case HttpURLConnection.HTTP_OK:
					while ((line = reader.readLine()) != null) {
						builder.append(line);	
					}
					responseStr = builder.toString();
					result = "请求成功";
					break;
				case HttpURLConnection.HTTP_BAD_REQUEST:
					while ((line = reader.readLine()) != null) {
						builder.append(line);
					}
					responseStr = builder.toString();
					result = "错误请求";
					break;
				case HttpURLConnection.HTTP_INTERNAL_ERROR:
					result = "服务器端错误";
					break;
				case HttpURLConnection.HTTP_NOT_FOUND:
					result = "未找到指定的网址";
					break;
				case HttpURLConnection.HTTP_BAD_GATEWAY:
					result = "请求超时";
					break;
				default:
					break;
				}
				
	
		} catch (Exception e) {
			e.printStackTrace();
			map.put("code", HttpURLConnection.HTTP_BAD_GATEWAY);
			map.put("result", "无法连接网络,请检查网络设置");
			map.put("response", "");
		}finally{
			map.put("code", responseCode);
			map.put("result", result);
			map.put("response", responseStr);
			logger.info("result:"+result);
			logger.info("responseStr:"+responseStr);
			logger.info("responseCode:"+responseCode);
		}
		
		return map;
	}
	
	
	
	public static void main(String[] args) throws Exception {
		HttpLongClient client = new HttpLongClient();
		String url = "http://127.0.0.1:8080/SSODemo/services/rest"; //http请求所访问的地址
		url="http://localhost:8080/testComet.do";
		Map<String, Object> data = null;

		String requestInfo="sdfsdf";
		String[] params = new String[]{"requestInfo",requestInfo};
		//发送请求包
		data = client.getHttpByPost(url, params);
		String responseInfo = (String) data.get("response");
		logger.error("resp:");
		logger.error(responseInfo);
		
		
		
		
	}
	
}

     客户端也可以采用ajax ,直接在web侧展现。

 

   

  

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics