`

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侧展现。

 

   

  

分享到:
评论

相关推荐

    CSharp HTTP长连接(Comet)

    在IT行业中,HTTP长连接(也称为Comet技术)是一种用于实现服务器向客户端实时推送数据的方法,常用于构建实时交互的应用,如聊天室、股票报价、在线游戏等。C#作为.NET框架的主要编程语言,提供了丰富的工具和技术...

    Comet(Http长连接)

    综上所述,Comet技术通过HTTP长连接实现了服务器向客户端的实时数据推送,显著改善了Web应用的交互体验。PHP和JavaScript结合,可以轻松构建出这样的实时应用实例。然而,Comet也存在一定的缺点,如服务器资源消耗较...

    Comet:基于 HTTP 长连接的“服务器推”技术 (实例)

    然而,Comet技术利用HTTP长连接,保持浏览器和服务器之间的连接不关闭,直到服务器有新的数据需要发送或者连接超时。这样,服务器可以在任何时刻向客户端推送数据,无需等待客户端的下一次请求。 **Comet 实现方式*...

    Java 实现 Comet 长连接,服务器主动发送消息给客户端

    Java 实现 Comet 长连接,服务器主动发送消息给客户端是一项关键的技术,它在实时通信、推送服务等领域有着广泛的应用。Comet 是一种基于 HTTP 的持久化连接技术,允许服务器在客户端保持一个打开的 HTTP 连接,直到...

    Comet:基于 HTTP 长连接的“服务器推”技术

    Comet:基于 HTTP 长连接的“服务器推”技术

    Comet:基于HTTP长连接的“服务器推”技术[收集].pdf

    【Comet技术详解:HTTP长连接的服务器推送】 在软件开发领域,尤其是在Web应用程序的设计中,"服务器推"技术已经成为解决实时数据传输需求的关键。传统的Web系统采用客户端发起请求、服务器响应的方式工作,但这并...

    Comet:基于_HTTP_长连接的“服务器推”技术

    Comet技术的核心是使用HTTP长连接,即客户端与服务器之间维持一个持久的连接状态,服务器可以随时通过这个连接将数据推送给客户端。相较于传统短连接,长连接可以显著减少每次数据交换所需的开销,提高效率。 #####...

    基于长连接的简易聊天室jQuery+.net 2.0 Comet

    基于长连接的简易聊天室jQuery+.net 2.0 Comet Comet练手,尚有不少bug,还未实现维护用户列表功能 是长连接的不是轮询方式 升级版本 http://download.csdn.net/source/2216847

    CometAsync_net:C#实现基于http长连接“服务器推”-Comet技术

    C#实现基于http长连接“服务器推”-Comet技术 很多应用譬如监控、即时通信、即时报价系统都需要将后台发生的变化实时传送到客户端而无须客户端不停地刷新、发送请求。 本项目基于 AJAX 的长轮询方式实现。 ...

    comet demo 向客户端推送例子

    Comet技术是一种基于HTTP长连接的反向Ajax技术,它允许服务器向客户端浏览器主动推送数据,从而实现双向通信。在Web应用中,通常的HTTP请求是客户端发起的,而Comet打破了这种模式,使得服务器可以在适当的时候主动...

    comet4j 所需js以及comet4j-tomcat6.jar、comet4j-tomcat7.jar包

    Comet4j是一种基于Java的实时通信框架,它利用了HTTP长连接技术,实现了服务器向客户端的高效、低延迟的消息推送。在这个压缩包中,包含了Comet4j框架运行所必需的一些关键组件。 首先,`comet4j.js`是Comet4j的...

    页面间隔半秒钟更新时间 Asp.net使用Comet开发http长连接示例分享

    页面间隔半秒钟更新时间***使用Comet开发http长连接示例分享,详细地介绍了如何使用Comet技术在***环境下,通过HTTP长连接实现页面定时更新的功能。 知识点一:Comet技术概述 Comet是一种Web应用模型,允许服务器端...

    http长连接

    ### HTTP长连接详解 HTTP(Hypertext Transfer Protocol)作为互联网上应用最为广泛的一种网络协议,主要用于从万维网服务器传输超文本到本地浏览器的传输协议。然而,传统的HTTP通信方式采用短连接模式,即每次...

    comet框架例子项目

    4. **HTTP长轮询**:这是Comet的一种实现方式,客户端发起一个HTTP请求,服务器保持连接并等待新数据,一旦有数据可用,就立即返回,客户端收到数据后再次发起请求,如此循环。 5. **HTTP流**:另一种Comet实现,...

    catalina-comet.jar

    2. ** 长连接与HTTP连接管理**:Comet技术依赖于长时间保持的HTTP连接,这与传统的HTTP请求-响应模型不同。Catalina-Comet.jar中的实现优化了连接管理,以确保在大量并发长连接的情况下服务器仍能高效运行。 3. ** ...

    【ASP.NET编程知识】页面间隔半秒钟更新时间 Asp.net使用Comet开发http长连接示例分享.docx

    【ASP.NET编程知识】页面间隔半秒钟更新时间Asp.net使用Comet开发HTTP长连接示例分享 在ASP.NET编程中,实现页面间隔半秒钟自动更新时间通常涉及到实时通信技术,这里提到了使用Comet技术。Comet是一种优化的HTTP...

    web推送 comet技术

    Comet技术是一种基于HTTP长连接的Web实时通信技术,它允许服务器向客户端主动推送数据,而无需客户端发起新的请求。这种技术打破了传统的HTTP请求-响应模型,极大地提升了Web应用的实时性和交互性,尤其适用于股票...

Global site tag (gtag.js) - Google Analytics