`
left.jessica
  • 浏览: 32656 次
  • 性别: Icon_minigender_2
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

基于AJAX的长轮询(long-polling)方式实现COMET例子

阅读更多

什么是 Comet?

解释: Alex Russell Dojo Toolkit 的项目 Lead )称这种基于 HTTP 长连接、无须在浏览器端安装插件的 服务器推 技术为 “Comet”

有两种实现 Comet 应用的实现模型,目前主要讨论的是基于 AJAX 的长轮询 (long-polling) 方式

例子如下:

Servlet实现类:TestComet


 

public class TestComet extends HttpServlet implements CometProcessor {
	
	private static final long serialVersionUID = 1L;

	// 发送器
	private MessageSender messageSender = null;

	private static final Integer TIMEOUT = 60 * 1000;

	@Override
	public void destroy() {
		messageSender.stop();
		messageSender = null;

	}

	@Override
	public void init() throws ServletException {
		System.out.println("--init-----------------");
		
		// 初始化发送器
		messageSender = new MessageSender();
		Thread messageSenderThread = new Thread(messageSender, "MessageSender["
				+ getServletContext().getContextPath() + "]");
		messageSenderThread.setDaemon(true);
		
		// 启动发送线程
		messageSenderThread.start();
	}

	public void event(final CometEvent event) throws IOException,
			ServletException {
		System.out.println("--event-----------------");
		
		// 获取事件对应的REQUEST 和 RESPONSE
		HttpServletRequest request = event.getHttpServletRequest();
		HttpServletResponse response = event.getHttpServletResponse();
		
		
		if (event.getEventType() == CometEvent.EventType.BEGIN) {
			request.setAttribute("org.apache.tomcat.comet.timeout", TIMEOUT);
			log("Begin for session: " + request.getSession(true).getId());
			// 注入RESPONSE
			messageSender.setConnection(response);
			
			Weatherman weatherman = new Weatherman(messageSender, 95118, 32408);
			new Thread(weatherman).start();
			
		} else if (event.getEventType() == CometEvent.EventType.ERROR) {
			log("Error for session: " + request.getSession(true).getId());
			event.close();
		} else if (event.getEventType() == CometEvent.EventType.END) {
			log("End for session: " + request.getSession(true).getId());
			event.close();
		} else if (event.getEventType() == CometEvent.EventType.READ) {
			throw new UnsupportedOperationException(
					"This servlet does not accept data");
		}
	}
}


 信息发送器:

public class MessageSender implements Runnable {

	// 标志位
	protected boolean running = true;

	// 信息列表
	protected final ArrayList<String> messages = new ArrayList<String>();

	// HTTP RESPONSE
	private ServletResponse connection;

	// 注入HTTP RESPONSE
	public synchronized void setConnection(ServletResponse connection) {
		this.connection = connection;
		notify();
	}

	// 发送信息
	public void send(String message) {
		// 同步队列,加入发送信息
		synchronized (messages) {
			messages.add(message);
			log("Message added #messages=" + messages.size());
			// 唤醒
			messages.notify();
		}
	}

	public void run() {

		// 线程启动
		log("start");
		while (running) {
			if (messages.size() == 0) {
				try {
					synchronized (messages) {
						log("MessageSender wait[空闲状态,线程等待]");
						// 释放锁
						messages.wait();
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
					// Ignore
				}
			}
			String[] pendingMessages = null;
			synchronized (messages) {
				
				// 导出发送的信息至数组
				pendingMessages = messages.toArray(new String[0]);
				// 清空信息队列
				messages.clear();
			}
			try {
				if (connection == null) {
					try {
						synchronized (this) {
							// 等待注入HTTP RESPONSE
							wait();
						}
					} catch (InterruptedException e) {
						// Ignore
						e.printStackTrace();
					}
				}
				
				// 输出流操作
				OutputStream out = connection.getOutputStream();
				for (int j = 0; j < pendingMessages.length; j++) {
					final String forecast = pendingMessages[j] + "<br>";
					out.write(forecast.getBytes());
					out.flush();
					connection.flushBuffer();
					log("Writing[写入]:" + forecast);
				}
			} catch (IOException e) {
				log("IOExeption sending message", e);
			}
		}
	}

	// 停止
	public void stop() {
		running = false;
	}

	// 日志
	private void log(Object obj) {
		System.out.println(obj);
	}

	// 日志
	private void log(Object obj, Throwable e) {
		System.out.println(obj);
		e.printStackTrace();
	}

}


 YAHOO天气预报:

public class Weatherman implements Runnable {

	// 链接列表
	private final List<URL> zipCodes;
	
	// YAHOO WEATHER
	private final String YAHOO_WEATHER = "http://weather.yahooapis.com/forecastrss?p=";
	
	// 发送器
	private MessageSender messageSender;

	public Weatherman(MessageSender messageSender, Integer... zips) {
		this.messageSender = messageSender;
		zipCodes = new ArrayList<URL>(zips.length);
		for (Integer zip : zips) {
			try {
				// 添加具体链接
				zipCodes.add(new URL(YAHOO_WEATHER + zip));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public void run() {
		System.out.println("Weatherman run[天气预报员启动]");
		int i = 0;
		while (i >= 0) {
			int j = i % zipCodes.size();
			SyndFeedInput input = new SyndFeedInput();
			try {
				SyndFeed feed = input.build(new InputStreamReader(zipCodes.get(
						j).openStream()));
				SyndEntry entry = (SyndEntry) feed.getEntries().get(0);
				
				// 发送数据
				messageSender.send(entryToHtml(entry));
				
				// 线程休眠
				Thread.sleep(10000L);
			} catch (Exception e) {
				e.printStackTrace();
			}
			i++;
		}
	}

	// 格式转换
	private String entryToHtml(SyndEntry entry) {
		StringBuilder html = new StringBuilder("<h2>");
		html.append(entry.getTitle());
		html.append("</h2>");
		html.append(entry.getDescription().getValue());
		return html.toString();
	}
}

 WEB.XML配置:

	<servlet>
	    <description>TestComet</description>
	    <display-name>TestComet</display-name>
	    <servlet-name>TestComet</servlet-name>
	    <servlet-class>cn.test.TestComet</servlet-class>
	</servlet>

	<servlet-mapping>
	    <servlet-name>TestComet</servlet-name>
	    <url-pattern>/TestComet</url-pattern>
	</servlet-mapping>

 TOMCAT配置,NIO

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


 


 

参考文档:

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

http://www.ibm.com/developerworks/cn/web/wa-lo-comet/

 

使用 Java 实现 Comet 风格的 Web 应用(一)

http://blog.csdn.net/ligaoyang/archive/2009/08/03/4402889.aspx

 

使用 Java 实现 Comet 风格的 Web 应用(二)

http://blog.csdn.net/ligaoyang/archive/2009/08/03/4402898.aspx


 

注:

以上例子只支持FIREFOX,不支持IE

可能会出现一些问题,例如有些包可能有冲突,需要在context.xml中添加

<Loader delegate="true" />


 

分享到:
评论
2 楼 zhdalong 2011-12-30  
public void event(final CometEvent event) throws IOException, 
            ServletException { }

什么时候调用
1 楼 neal 2011-04-12  
按照这个搭出来运行报错,能否打包整个发给我

相关推荐

    长轮询Prototype+comet源代码

    长轮询(Long Polling)和Comet技术是Web实时通信(Real-Time Web Communication)中的两种重要机制,它们主要用于实现服务器向客户端的即时数据推送,而不再局限于传统的HTTP请求-响应模式。在本文中,我们将深入...

    jquery与php结合实现AJAX长轮询(LongPoll)

    在介绍如何使用jQuery和PHP结合实现AJAX长轮询(Long Polling)之前,我们需要先了解几个关键点:传统的AJAX轮询方式、服务器推送技术(Comet)、以及HTTP协议的基本特性。 传统的AJAX轮询方式是一种客户端定期向...

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

    Comet 技术主要分为两种实现方式:HTTP 长轮询(Long Polling)和 HTTP 流(HTTP Streaming)。长轮询是客户端发起请求,服务器在没有新数据时保持连接不关闭,直到有新数据或达到预设超时时间才返回响应并关闭连接...

    网易邮箱的Comet实践_陈志凌(网易)

    Comet技术有几种实现方式,包括长轮询(Long-polling)和流方式(Streaming)等。 - 长轮询(Long-polling)模式下,浏览器向服务器发起一个请求,服务器保持该请求开启状态直到有数据可发送或超时。这种模式保证了实时...

    asp.net+jquery长轮询实例

    长轮询(Long Polling)是解决这一问题的一种策略。在这个实例中,客户端使用jQuery发起一个请求到服务器,服务器接收到请求后并不立即返回,而是保持这个连接打开,直到有新的数据更新或者达到预设的超时时间。一旦...

    tomcat+comet实现终端与服务端同步的小例子

    1. **长轮询(Long-Polling)**:客户端发起请求,服务器保持连接直到有新数据可发送,然后才返回响应并关闭连接。 2. **HTTP流(HTTP Streaming)**:服务器在响应头中设置适当的Content-Length或Transfer-Encoding...

    3.1.1.Web应用从服务器主动推送Data到客户端有那些方式.doc

    1. **AJAX轮询(Long-Polling)**: AJAX轮询是客户端定期向服务器发送请求,询问是否有新数据的一种简单方法。然而,这种方法存在明显的缺点:频繁的请求可能导致服务器资源浪费,增加网络负载。为了优化,出现了...

    反向ajax

    `comet-long-polling`文件可能涉及长轮询这一Comet技术的实现方式。长轮询是客户端发起一个Ajax请求,服务器接收到请求后不立即响应,而是保持连接打开状态,直到有新数据可用时才返回响应,或者超时关闭连接。这种...

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

    4. **Long Polling**(长轮询):与普通轮询不同,长轮询会保持请求开放,直到服务器有新数据或连接超时。这种方式比普通轮询更高效,因为它减少了不必要的请求。 5. **IFrame 和 Script Tags**:通过嵌入隐藏的...

    comet-ajax.rar

    Comet主要有两种实现方式: 1. 长轮询(Long Polling):客户端发起一个HTTP请求,服务器保持连接不关闭,直到有新数据时才返回,或者达到预设的超时时间后关闭连接。客户端接收到数据后立即发起新的请求,形成循环...

    comet4j+tomcat7 demo

    Comet4j是一个开源的Java库,专门设计用于实现Comet技术,即长轮询(Long Polling)和HTTP流,以实现在Web应用中提供实时通信的能力。这个Demo包含了源代码和操作手册,帮助开发者快速理解和应用Comet4j。 在Web...

    Ajax和Comet技术总结

    Comet有多种实现方式,包括长轮询(Long Polling)、流(Streaming)、iframe和WebSocket等。长轮询是Comet的一种常见实现,服务器在接收到请求后不会立即返回,而是保持连接直到有新数据可用,然后发送数据并关闭...

    comet-jquery

    【comet-jquery】是一种基于jQuery的实时通信技术,它利用了Comet技术来实现服务器向客户端推送数据的功能。在Web开发中,传统的HTTP协议是请求-响应模式,即客户端发起请求,服务器返回数据,而Comet技术打破了这种...

    浅析Comet技术在Java Web实时系统开发中的应用.pdf

    1. 长轮询(Long-polling):客户端发起请求,服务器接收到请求后并不立即响应,而是保持连接状态,直到有新的数据或达到超时时间才返回响应。客户端收到响应后会立即重新发起请求,保持连接的循环状态。长轮询的...

    my_comet_demo.rar_DEMO_comet

    Comet主要有两种实现方式:长轮询(Long Polling)和HTTP流(HTTP Streaming)。长轮询是客户端发起一个请求,服务器在没有新数据时保持连接不关闭,直到有数据可用时才返回响应,客户端再发起新的请求。HTTP流则是...

    浅析Comet技术在Java Web实时系统开发中的应用.docx

    Comet技术主要有两种实现方式:长轮询(Long-Polling)和流(Streaming)。 1. 长轮询:客户端发送请求到服务器,服务器保持连接开放,直到有新数据可用或达到预设的超时时才返回响应。客户端接收到响应后立即再次...

    ajax 、jsp实现的聊天室代码

    4. **实时通信**:为了实现即时聊天,可能采用了长轮询(Long Polling)、Comet、WebSocket等技术。Ajax可以轻松实现长轮询,通过保持一个持续的HTTP连接,直到服务器有新数据可返回。 5. **安全性**:确保聊天室的...

    Comet link

    1. 长轮询(Long Polling):客户端发起一个HTTP请求,服务器接收到请求后不立即返回,而是保持连接状态,直到有新数据可推送给客户端或超时才关闭连接。客户端接收到数据后立即重新发起请求,形成一个持续的交互...

    comet_jquery

    【标题】"comet_jquery"是一个Java Web项目,它实现了基于流(Stream)和长轮询(Long Polling)的长连接技术。这个项目旨在提供一个高效且可靠的实时通信解决方案,尤其适用于需要实时更新数据的Web应用,如聊天、...

Global site tag (gtag.js) - Google Analytics