- 浏览: 3123 次
- 性别:
- 来自: 大连
文章分类
最新评论
闲来无事 一直想把以前做的一小块comet应用写个博客记下来
当初用的时候没找到比较好的例子 一边摸索一边鼓捣
今天写下来给需要的人参阅一下。。
Comet是基于 HTTP 长连接的“服务器推”技术
服务器推”是一种很早就存在的技术,以前在实现上主要是通过客户端的套接口,或是服务器端的远程调用。因为浏览器技术的发展比较缓慢,没有为“服务器推”的实现提供很好的支持,在纯浏览器的应用中很难有一个完善的方案去实现“服务器推”并用于商业程序。最近几年,因为 AJAX 技术的普及,以及把 IFrame 嵌在“htmlfile“的 ActiveX 组件中可以解决 IE 的加载显示问题,一些受欢迎的应用如 meebo,gmail+gtalk 在实现中使用了这些新技术;同时“服务器推”在现实应用中确实存在很多需求。因为这些原因,基于纯浏览器的“服务器推”技术开始受到较多关注,Alex Russell(Dojo Toolkit 的项目 Lead)称这种基于 HTTP 长连接、无须在浏览器端安装插件的“服务器推”技术为“Comet”。目前已经出现了一些成熟的 Comet 应用以及各种开源框架;一些 Web 服务器如 Jetty 也在为支持大量并发的长连接进行了很多改进。
一般我是极其反感看此类的简介,因为你看了半天你根本不知道他在讲什么,一堆废话,一堆术语和关键字。
大白话来讲comet就是抓住HTTP请求不释放,攥在手里,等你想要释放的时候在释放。所以就有了推的感觉。
某人给你打电话,你接起电话寒暄一阵挂断,就完成了此次事件。但是过了2分钟你想起有个事没说,你却找不到他了(没有来电显示,对方使用公共匿名电话拨打)。为了避免这种情况发生,就出现了轮训,何为轮训就是使用匿名公共电话的人一分钟给你打一次电话,以防你有事忘了说。这样在现实中就完蛋了,啥也不用干,一天就打电话得了。
换到我们互联网应用,因为他是机器,没有状态和感情,不用考虑他感受,但是这么做长久的轮训也会造成客户端浏览器假死,而被轮训的,或者说接电话的就会累死。他同时要准备接听无数个电话,迫使他做出开辟一个新的房间,弄了个总机,分成无数个分机同时准备接电话。这就是蛋疼的轮训。
而comet的意思就是,你给我打电话,OK 我接起来,一直不挂掉,没话就不说,想起来什么什么时候说,当然这么做也会有压力。。。电话费啊(服务端和客户端一直占用,不断开。。。)
罗哩叭嗦一大堆 正题来了。
先看页面代码
定义请求的服务器地址和servlet 添加上你的用户ID为后面推送做准备
这段代码是在哪找的忘了。。。识别各种浏览器添加iframe并开启事件。
木有什么好说明的。
下面是servlet的服务端代码
注释写的不是很全面 代码应该很容易懂的
在附件内我将完整的代码传上来包括页面的JS和后台的几个class。。。如果用的话直接看看没什么问题。
同样 你需要修改tomcat 目录下conf文件夹下的server.xml
当初用的时候没找到比较好的例子 一边摸索一边鼓捣
今天写下来给需要的人参阅一下。。
Comet是基于 HTTP 长连接的“服务器推”技术
引用
服务器推”是一种很早就存在的技术,以前在实现上主要是通过客户端的套接口,或是服务器端的远程调用。因为浏览器技术的发展比较缓慢,没有为“服务器推”的实现提供很好的支持,在纯浏览器的应用中很难有一个完善的方案去实现“服务器推”并用于商业程序。最近几年,因为 AJAX 技术的普及,以及把 IFrame 嵌在“htmlfile“的 ActiveX 组件中可以解决 IE 的加载显示问题,一些受欢迎的应用如 meebo,gmail+gtalk 在实现中使用了这些新技术;同时“服务器推”在现实应用中确实存在很多需求。因为这些原因,基于纯浏览器的“服务器推”技术开始受到较多关注,Alex Russell(Dojo Toolkit 的项目 Lead)称这种基于 HTTP 长连接、无须在浏览器端安装插件的“服务器推”技术为“Comet”。目前已经出现了一些成熟的 Comet 应用以及各种开源框架;一些 Web 服务器如 Jetty 也在为支持大量并发的长连接进行了很多改进。
一般我是极其反感看此类的简介,因为你看了半天你根本不知道他在讲什么,一堆废话,一堆术语和关键字。
大白话来讲comet就是抓住HTTP请求不释放,攥在手里,等你想要释放的时候在释放。所以就有了推的感觉。
某人给你打电话,你接起电话寒暄一阵挂断,就完成了此次事件。但是过了2分钟你想起有个事没说,你却找不到他了(没有来电显示,对方使用公共匿名电话拨打)。为了避免这种情况发生,就出现了轮训,何为轮训就是使用匿名公共电话的人一分钟给你打一次电话,以防你有事忘了说。这样在现实中就完蛋了,啥也不用干,一天就打电话得了。
换到我们互联网应用,因为他是机器,没有状态和感情,不用考虑他感受,但是这么做长久的轮训也会造成客户端浏览器假死,而被轮训的,或者说接电话的就会累死。他同时要准备接听无数个电话,迫使他做出开辟一个新的房间,弄了个总机,分成无数个分机同时准备接电话。这就是蛋疼的轮训。
而comet的意思就是,你给我打电话,OK 我接起来,一直不挂掉,没话就不说,想起来什么什么时候说,当然这么做也会有压力。。。电话费啊(服务端和客户端一直占用,不断开。。。)
罗哩叭嗦一大堆 正题来了。
先看页面代码
定义请求的服务器地址和servlet 添加上你的用户ID为后面推送做准备
这段代码是在哪找的忘了。。。识别各种浏览器添加iframe并开启事件。
木有什么好说明的。
var server = '<%=basePath%>SiteInfo?userId=<%=session.getAttribute("userId")%>'; var comet = { connection : false, iframediv : false, initialize: function() { if (navigator.appVersion.indexOf("MSIE") != -1) { comet.connection = new ActiveXObject("htmlfile"); comet.connection.open(); comet.connection.write("<html>"); comet.connection.write("<script>document.domain = '"+document.domain+"'"); comet.connection.write("</html>"); comet.connection.close(); comet.iframediv = comet.connection.createElement("div"); comet.connection.appendChild(comet.iframediv); comet.connection.parentWindow.comet = comet; comet.iframediv.innerHTML = "<iframe id='comet_iframe' src='"+server+"'></iframe>"; } else if (navigator.appVersion.indexOf("KHTML") != -1) { comet.connection = document.createElement('iframe'); comet.connection.setAttribute('id', 'comet_iframe'); comet.connection.setAttribute('src', server); with (comet.connection.style) { position = "absolute"; left = top = "-100px"; height = width = "1px"; visibility = "hidden"; } document.body.appendChild(comet.connection); } else { comet.connection = document.createElement('iframe'); comet.connection.setAttribute('id', 'comet_iframe'); with (comet.connection.style) { left = top = "-100px"; height = width = "1px"; visibility = "hidden"; display = 'none'; } comet.iframediv = document.createElement('iframe'); comet.iframediv.setAttribute('src', server); comet.connection.appendChild(comet.iframediv); document.body.appendChild(comet.connection); } }, //添加私人消息 //这里是回调方法 privateMessage: function(data){ // alert("有新消息!"); $.messager.anim('show',1000); $.messager.show(0,'<a href="Site_listReceive.action">您有'+data+'条新短信!</a>'); }, //退出 // onUnload: function() { // if (comet.connection) { // comet.connection = false; //} //} }//comet end <%}%> if (window.addEventListener) { window.addEventListener("load", comet.initialize, false); // window.addEventListener("unload", comet.onUnload, false); } else if (window.attachEvent) { window.attachEvent("onload", comet.initialize); // window.attachEvent("onunload", comet.onUnload); }
下面是servlet的服务端代码
注释写的不是很全面 代码应该很容易懂的
package com.gmako.web.comet; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.InputStreamReader; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.ServletResponse; import org.apache.catalina.CometEvent; import org.apache.catalina.CometProcessor; import org.springframework.context.ApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; import com.gmako.entity.UserInfo; import com.gmako.service.ISiteInformationService; import com.gmako.service.impl.SiteInformationServiceImpl; public class SiteInfoServlet extends HttpServlet implements CometProcessor { private static final long serialVersionUID = -3667180332947986301L; private static MessageSender messageSender = null; // <用户,长连接> //声明两个MAP 用来存储response和request protected static Map<String, HttpServletResponse> connections = new HashMap<String, HttpServletResponse>(); protected static Map<String, HttpServletRequest> requests = new HashMap<String, HttpServletRequest>(); private static final Integer TIMEOUT = 60 * 1000; @Override public void destroy() { messageSender.stop(); messageSender = null; } @Override public void init() throws ServletException { 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 { HttpServletRequest request = event.getHttpServletRequest();//获取请求响应 HttpServletResponse response = event.getHttpServletResponse(); String userId = (String) request.getParameter("userId"); if(userId==null||"".equals(userId)){ //判断用户 return; } if (event.getEventType() == CometEvent.EventType.BEGIN) {//获取事件 event.setTimeout(Integer.MAX_VALUE);//设置过期时间 log("Begin for session: " + request.getSession(true).getId()+"userId是:"+userId); PrintWriter writer = response.getWriter(); writer .println("<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">"); writer .println("<html><head><script type=\"text/javascript\">var comet = window.parent.comet;</script></head><body>"); writer.println("<script type=\"text/javascript\">"); writer.println("var comet = window.parent.comet;"); writer.println("</script>"); writer.flush(); // for chrome if (request.getHeader("User-Agent").contains("KHTML")) { for (int i = 0; i < 100; i++) { writer.print("<input type=hidden name=none value=none>"); } writer.flush(); } System.out.println("链接的IP是:"+request.getLocalAddr()); System.out.println("链接的IP是:"+request.getHeaderNames()); if (userId != null||!("".equals(userId))) { //讲response和request放入集合中 以用户ID为key synchronized (connections) { connections.put(userId, response); } synchronized (requests) { requests.put(userId + "", request); } } } else if (event.getEventType() == CometEvent.EventType.ERROR) { log("Error for session: " + request.getSession(true).getId()+"userId是:"+userId+",非正常断开!"); if (userId != null) { synchronized (connections) { connections.remove(userId); } synchronized (requests) { requests.remove(userId); } } event.close(); } else if (event.getEventType() == CometEvent.EventType.END) { log("End for session: " + request.getSession(true).getId()+"userId是:"+userId+",正常断开!"); if (userId != null) { synchronized (connections) { connections.remove(userId); } synchronized (requests) { requests.remove(userId); } } event.close(); } } public static void send(int userId) { System.out.println("传过来的userId是" + userId); if(messageSender != null){ messageSender.send(userId + ""); //调用send方法 } } public void start() { } private class MessageSender implements Runnable { protected boolean running = true; protected final ArrayList<String> messages = new ArrayList<String>(); public void stop() { running = false; } /** * Add message for sending. 添加要发送的消息到消息队列内 */ public void send(String message) { synchronized (messages) { messages.add(message); log("Message added #messages=" + messages.size()); messages.notify(); } } public void run() { while (running) { if (messages.size() == 0) { //看队列内是否有消息 如果没有暂停该线程 try { synchronized (messages) { messages.wait(); } } catch (InterruptedException e) { // Ignore } } String[] pendingMessages = null; synchronized (messages) { //将消息集合内容传递给该数组 并清空集合 以便线程停止 pendingMessages = messages.toArray(new String[0]); messages.clear(); } if (connections == null) { //判断response集合是否有等待的 try { synchronized (this) { wait(); } } catch (InterruptedException e) { // Ignore } } if (requests == null) { //判断request集合是否有等待的 try { synchronized (this) { wait(); } } catch (InterruptedException e) { // Ignore } } HttpServletResponse res = null; PrintWriter writer = null; for (int j = 0; j < pendingMessages.length; j++) { System.out.println(requests.size()); System.out.println("消息队列里面的值是:" + pendingMessages[j]); if (connections.get(pendingMessages[j]) != null) { //以用户ID为key取出该用户的response 并直接打印 res = connections //由于前段为AJAX请求 所以可以直接通过该回调获取打印内容 .get(pendingMessages[j]); try { writer = res.getWriter(); } catch (IOException e) { e.printStackTrace(); } System.out.println("我发了消息!"); writer .print("<script type=\"text/javascript\">"); writer.println("comet.privateMessage('" + 1 + "');"); writer.print("</script>"); writer.flush(); log("Writing:" + "发送了一条推送给" + pendingMessages[j].toString()); writer.flush(); // writer.close(); } } log("Closing connection"); } } }
在附件内我将完整的代码传上来包括页面的JS和后台的几个class。。。如果用的话直接看看没什么问题。
同样 你需要修改tomcat 目录下conf文件夹下的server.xml
<Connector port="8088" connectionTimeout="20000" protocol="org.apache.coyote.http11.Http11NioProtocol" redirectPort="8443" useBodyEncodingForURI="true" URIEncoding="utf-8" />
- comet.zip (3.5 KB)
- 下载次数: 53
发表评论
文章已被作者锁定,不允许评论。
相关推荐
Comet4J开发指南 Comet4J是一个专为Java平台设计的服务器推送技术框架,它充分利用了AJAX(XMLHttpRequest)技术,实现了一种高效、实时的双向通信机制。在传统的HTTP协议中,服务器与客户端的交互是基于请求-响应...
综上所述,这个压缩包包含的`comet4j.js`、`comet4j-tomcat6.jar`和`comet4j-tomcat7.jar`是实现基于Java的Comet4j实时通信框架的关键组件。它们分别负责客户端的JavaScript交互、在Tomcat服务器上的集成和支持,为...
这个"comet demo"是一个展示如何在Java环境下利用Tomcat服务器实现Comet技术的实例。Tomcat 6.0是Apache软件基金会开发的开源Servlet容器,支持各种Java Web应用的部署,包括Comet技术。 首先,Comet的核心在于保持...
Comet4j是一个Java库,专门用于实现Comet技术,这是一种服务器向客户端推送数据的Web应用程序设计模式。Comet技术打破了传统的HTTP请求-响应模型,允许服务器在客户端保持持久连接,从而实现实时数据更新。这在需要...
在本"Comet框架例子项目"中,我们可以深入理解并学习如何利用Comet技术构建实时通信的应用。 Comet的核心理念是通过长时间保持一个HTTP连接来实现服务器到客户端的数据推送,而不是每次有新数据时都创建新的连接。...
Comet4J是一款针对Java平台的长连接技术框架,它主要设计用于实现高效的服务器推送技术。在Web开发中,服务器通常使用HTTP协议与客户端进行通信,而HTTP协议是基于请求-响应模型的,即客户端发起请求,服务器返回...
Comet4j是一个Java库,专门用于实现Comet技术,这是一种服务器推送技术,允许服务器向客户端实时推送数据,而不仅仅是响应客户端的请求。在Web应用中,这种技术常用于实现聊天室、股票报价、在线游戏等实时交互功能...
在MyEclipse集成开发环境中,你可以创建一个新的Web项目,导入`comet4j`库,然后按照Comet4J的API和文档编写服务器端的推送逻辑。客户端通常需要JavaScript来接收并处理服务器推送的数据,这可能涉及到AJAX或者...
【Catalina-Comet.jar】是Apache Tomcat服务器中用于支持Comet技术的一个关键组件。Comet是一种在Web开发中实现服务器推送技术的方法,它允许服务器主动向客户端发送数据,而不仅仅是响应客户端的请求。这种技术对于...
【标题】"comet4j完整包"是一个与Web服务端推送技术相关的软件包,它包含了一系列用于实现实时通信的组件和库。这个包旨在帮助开发者构建基于Comet技术的应用,以提供高效的、双向的服务器到客户端的数据传输。 ...
tomcat实现comet例子,实现后台产生每隔几秒产生随机数,前台不刷新显示。tomcat实现comet例子,实现后台产生每隔几秒产生随机数,前台不刷新显示。tomcat实现comet例子,实现后台产生每隔几秒产生随机数,前台不...
提供的文档应该包含了Comet4j的安装指南、API参考、示例代码和最佳实践。这些资源对于理解和使用Comet4j框架至关重要,可以帮助开发者快速上手。 5. **jar文件**: 包含的jar文件是Comet4j的库文件,需要将其添加...
标题中的"comet4j-tomcat6.jar"和"comet4j-tomcat7.jar"是针对Tomcat 6和7版本的特定兼容库。这两个JAR文件包含了Comet4j的核心组件,使得开发者能够在这些版本的Tomcat上部署和运行支持Comet的Web应用程序。它们...
"Comet Demo" 是一个展示Comet技术实际应用的示例项目,用户可以下载并运行来体验其功能。 在描述中提到,"Comet下载既可以运行",这意味着这个Demo是可执行的,用户下载后无需额外的构建或配置步骤,可以直接启动...
【标题】:“配置Tomcat支持Comet” 在Web开发中,传统的HTTP协议是基于请求-响应模型的,服务器端等待客户端发起请求,然后响应。但有些应用,如实时聊天、股票更新、在线游戏等,需要服务器能够主动推送数据到...
《Python库Comet_ml-2.0.12:跟踪、优化与实验管理》 在IT行业中,Python作为一门强大的开发语言,拥有丰富的库支持,其中Comet_ml就是一款专为机器学习和深度学习项目提供实验跟踪、模型优化以及协作功能的库。...
ASP.NET Comet是一个技术概念,它涉及到了Web应用程序中的实时通信,特别是服务器向客户端推送数据的能力。在传统的HTTP协议中,服务器通常在客户端发起请求时才响应,而在Comet模式下,服务器可以保持一个连接开放...
**C# Web即时通讯Comet框架详解** 在Web开发中,传统的HTTP协议是基于请求-响应模型的,这种模式在处理实时性需求时显得力不从心,因为服务器只有在接收到客户端的请求后才会返回数据。为了实现Web即时通讯(Web ...
在提供的`Comet.Test`文件中,可能包含一个用于测试Comet实现的WinForm应用程序。你可以运行此程序,观察客户端如何与服务器保持连接并接收数据。使用调试工具如Visual Studio,可以跟踪代码执行,检查HTTP请求和...