java 使用 comet4j 主动向客户端推送信息 简单例子
【背景】
今天,一个前端的师弟问我怎样做实时聊天窗口,我毫不犹豫地说:在前台定时访问服务端呀!师弟默默地百度了一番,最后告诉我,有一种技术是后服务端动推送信息给客户端的,这种技术的名字叫comet,我惊呆了,因为完全没听过,赶紧上网搜集资料,耗了一个晚上写了个简单的例子,实现主动向客户端发送信息。说是说主动,其实还是要客户端先献出它的“第一次”,即只要它有先请求你一下,以后你们熟了,你想主动约它就约它!
关于comet技术介绍及其实现原理,可以参考网站 http://www.ibm.com/developerworks/cn/web/wa-lo-comet/ 的介绍。
简单来说,就是客户端发送请求到服务端,服务器端会阻塞请求直到有数据传递或超时才返回,之后客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。当客户端处理接收的数据、重新建立连接时,服务器端可能有新的数据到达;这些信息会被服务器端保存直到客户端重新建立连接,客户端会一次把当前服务器端所有的信息取回。
【工作环境】
1、myeclipse2013
2、tomcat 6.0
3、jdk 7
4、火狐浏览器
说明:
测试成功的浏览器有:(1)火狐浏览器 (2)IE10、IE9、IE8 (3)360极速浏览器极速模式
测试失败的浏览器有:(1)IE10兼容模式、IE7
【准备工作】
1、下载comet4j.js :http://files.cnblogs.com/xiaoMzjm/comet4j.js.rar
2、下载comet4j-tomcat6.jar :http://files.cnblogs.com/xiaoMzjm/comet4j-tomcat6.jar.rar
3、到tomcat目录下——conf——server.xml 下,把
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
修改成:
<Connector URIEncoding="UTF-8"
connectionTimeout="20000"
port="8080"
protocol="org.apache.coyote.http11.Http11NioProtocol"
redirectPort="8443"
/>
说明:
其实那个js文件和jar官网是https://code.google.com/p/comet4j/ 的,但它是谷歌,这里是天朝呐,所以贴了两个我文件夹里面的包的地址上来。
comet4j-tomcat6.jar 还有另一个版本是 comet4j-tomcat7.jar , 自己选择合适的版本去下载。6以下的tomcat肯定不行就对了。
comet4j.js 的官方使用文档: http://doc.comet4j.tk/jsdocs/
comet4j-tomcat6.jar 的官方使用文档: http://doc.comet4j.tk/apidocs/
【新建项目过程】
(1)新建服务端的类TestComet , 实现 ServletContextListener 接口
(2)在web.xml 里面应该配置 拦截器:

<listener>
<listener-class>org.comet4j.core.CometAppListener</listener-class>
</listener>
<listener>
<description>HelloWorld</description>
<listener-class>com.zjm.www.test.TestComet</listener-class>
</listener>
<servlet>
<display-name>CometServlet</display-name>
<servlet-name>CometServlet</servlet-name>
<servlet-class>org.comet4j.core.CometServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CometServlet</servlet-name>
<url-pattern>/conn</url-pattern>
</servlet-mapping>

注:其中的要配置的有两个地方
一个是comet4j-tomcat6.jar下的一个servlet:org.comet4j.core.CometServlet , 客户端访问的入口
另一个是comet4j-tomcat6.jar下的监听器:org.comet4j.core.CometAppListener , 监听我们自己的类。
【具体代码(说明都写在注释里面)】
1、web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<listener>
<listener-class>org.comet4j.core.CometAppListener</listener-class>
</listener>
<listener>
<description>HelloWorld</description>
<listener-class>com.zjm.www.test.TestComet</listener-class>
</listener>
<servlet>
<display-name>CometServlet</display-name>
<servlet-name>CometServlet</servlet-name>
<servlet-class>org.comet4j.core.CometServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CometServlet</servlet-name>
<url-pattern>/conn</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="2.5" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 7 <listener> 8 <listener-class>org.comet4j.core.CometAppListener</listener-class> 9 </listener> 10 <listener> 11 <description>HelloWorld</description> 12 <listener-class>com.zjm.www.test.TestComet</listener-class> 13 </listener> 14 <servlet> 15 <display-name>CometServlet</display-name> 16 <servlet-name>CometServlet</servlet-name> 17 <servlet-class>org.comet4j.core.CometServlet</servlet-class> 18 </servlet> 19 <servlet-mapping> 20 <servlet-name>CometServlet</servlet-name> 21 <url-pattern>/conn</url-pattern> 22 </servlet-mapping> 23 24 25 <welcome-file-list> 26 <welcome-file>index.jsp</welcome-file> 27 </welcome-file-list> 28 </web-app>

2、java类TestComet
里面附上了不少的注释,如果想仔细研究建议看上面的赋予的API文档链接。
package com.zjm.www.test;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.comet4j.core.CometContext;
import org.comet4j.core.CometEngine;
/**
* 描述:服务端主动推送消息到客户端 简单例子
* @author zjm
* @time 2014/8/7
*/
public class TestComet implements ServletContextListener {
// 频道1
private static final String CHANNEL1 = "result1";
// 频道2
private static final String CHANNEL2 = "result2";
// 通过频道1推送给前台的变量1
private static int number1 = 0 ;
// 通过频道2推送给前台的变量2
private static int number2 = 100 ;
/**
* 初始化上下文
*/
public void contextInitialized(ServletContextEvent arg0) {
// CometContext : Comet4J上下文,负责初始化配置、引擎对象、连接器对象、消息缓存等。
CometContext cc = CometContext.getInstance();
// 注册频道,即标识哪些字段可用当成频道,用来作为向前台传送数据的“通道”
cc.registChannel(CHANNEL1);
cc.registChannel(CHANNEL2);
Thread myThread = new Thread(new SendToClientThread(), "SendToClientThread");
// 下面的内部类的方法是个死循环,设置helloAppModule线程为“守护线程”,则当jvm只剩“守护线程”时(主线程结束),该线程也会结束。
myThread.setDaemon(true);
// 开始线程
myThread.start();
}
/**
* 内部类线程类
*/
class SendToClientThread implements Runnable {
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (Exception ex) {
ex.printStackTrace();
}
// CometEngine : 引擎,负责管理和维持连接,并能够必要的发送服务
CometEngine engine = CometContext.getInstance().getEngine();
// 参数的意思:通过什么频道(CHANNEL1)发送什么数据(number1++),前台可用可用频道的值(result1)来获取某频道发送的数据
engine.sendToAll(CHANNEL1, number1++);
engine.sendToAll(CHANNEL2, number2++);
}
}
}
public void contextDestroyed(ServletContextEvent arg0) {
}
}

1 package com.zjm.www.test;
2
3 import javax.servlet.ServletContextEvent;
4 import javax.servlet.ServletContextListener;
5
6 import org.comet4j.core.CometContext;
7 import org.comet4j.core.CometEngine;
8
9 /**
10 * 描述:服务端主动推送消息到客户端 简单例子
11 * @author zjm
12 * @time 2014/8/7
13 */
14 public class TestComet implements ServletContextListener {
15
16 // 频道1
17 private static final String CHANNEL1 = "result1";
18 // 频道2
19 private static final String CHANNEL2 = "result2";
20
21 // 通过频道1推送给前台的变量1
22 private static int number1 = 0 ;
23 // 通过频道2推送给前台的变量2
24 private static int number2 = 100 ;
25
26 /**
27 * 初始化上下文
28 */
29 public void contextInitialized(ServletContextEvent arg0) {
30
31 // CometContext : Comet4J上下文,负责初始化配置、引擎对象、连接器对象、消息缓存等。
32 CometContext cc = CometContext.getInstance();
33 // 注册频道,即标识哪些字段可用当成频道,用来作为向前台传送数据的“通道”
34 cc.registChannel(CHANNEL1);
35 cc.registChannel(CHANNEL2);
36
37 Thread myThread = new Thread(new SendToClientThread(), "SendToClientThread");
38 // 下面的内部类的方法是个死循环,设置helloAppModule线程为“守护线程”,则当jvm只剩“守护线程”时(主线程结束),该线程也会结束。
39 myThread.setDaemon(true);
40 // 开始线程
41 myThread.start();
42 }
43
44 /**
45 * 内部类线程类
46 */
47 class SendToClientThread implements Runnable {
48 public void run() {
49 while (true) {
50 try {
51 Thread.sleep(1000);
52 } catch (Exception ex) {
53 ex.printStackTrace();
54 }
55 // CometEngine : 引擎,负责管理和维持连接,并能够必要的发送服务
56 CometEngine engine = CometContext.getInstance().getEngine();
57 // 参数的意思:通过什么频道(CHANNEL1)发送什么数据(number1++),前台可用可用频道的值(result1)来获取某频道发送的数据
58 engine.sendToAll(CHANNEL1, number1++);
59 engine.sendToAll(CHANNEL2, number2++);
60 }
61 }
62 }
63
64 public void contextDestroyed(ServletContextEvent arg0) {
65 }
66 }

3、客户端代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Comet4J Hello World</title>
<script type="text/javascript" src="js/comet4j.js"></script>
<script type="text/javascript">
function init(){
var number1 = document.getElementById('number1');
var number2 = document.getElementById('number2');
// 建立连接,conn 即web.xml中 CometServlet的<url-pattern>
JS.Engine.start('conn');
// 监听后台某个频道
JS.Engine.on(
{
// 对应服务端 “频道1” 的值 result1
result1 : function(num1){
number1.innerHTML = num1;
},
// 对应服务端 “频道2” 的值 result2
result2 : function(num2){
number2.innerHTML = num2;
},
}
);
}
</script>
</head>
<body onload="init()">
数字1:<span id="number1">...</span><br></br>
数字2:<span id="number2">...</span>
</body>
</html>

1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2 <html xmlns="http://www.w3.org/1999/xhtml">
3 <head>
4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>Comet4J Hello World</title>
6 <script type="text/javascript" src="js/comet4j.js"></script>
7 <script type="text/javascript">
8 function init(){
9
10 var number1 = document.getElementById('number1');
11 var number2 = document.getElementById('number2');
12 // 建立连接,conn 即web.xml中 CometServlet的<url-pattern>
13 JS.Engine.start('conn');
14 // 监听后台某个频道
15 JS.Engine.on(
16 {
17 // 对应服务端 “频道1” 的值 result1
18 result1 : function(num1){
19 number1.innerHTML = num1;
20 },
21 // 对应服务端 “频道2” 的值 result2
22 result2 : function(num2){
23 number2.innerHTML = num2;
24 },
25 }
26 );
27 }
28 </script>
29 </head>
30 <body onload="init()">
31 数字1:<span id="number1">...</span><br></br>
32 数字2:<span id="number2">...</span>
33 </body>
34 </html>

4、网页显示
数字1:2221 数字2:2321
可以看出,两个数字不停地每秒递增。数字2比数字1 多了100,因为在服务端,number2的初始值为100,number1的初始值为0。
在浏览器上按F12,选择netWork,如下图,可以看出,此连接从未断开过。

有什么写错或写得不好的地方,欢迎大家提出来~
java 使用 comet4j 主动向客户端推送信息 简单例子的更多相关文章
- pushlet实现服务器端向客户端推送信息
使用Pushlet来实现服务器端向客户端推送信息 1. 实现方式: 有两种实现方式: 1. 通过配置文件来实现定时的从服务器端向客户端推送信息 2. 通过API主动 ...
- 使用Pushlet来实现服务器端向客户端推送信息
使用Pushlet来实现服务器端向客户端推送信息 1. 实现方式: 有两种实现方式: 1. 通过配置文件来实现定时的从服务器端向客户端推送信息 2. 通过A ...
- 5.Android消息推送机制简单例子
1.首先布局文件xml代码: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout x ...
- SpringBoot2.0集成WebSocket,实现后台向前端推送信息
感谢作者,支持原创: https://blog.csdn.net/moshowgame/article/details/80275084 什么是WebSocket? WebSocket协议是基于TCP ...
- Android高效率编码-第三方SDK详解系列(三)——JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送
Android高效率编码-第三方SDK详解系列(三)--JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送 很久没有更新第三方SDK这个系列了,所以更新一下这几天工作中使用到的推送, ...
- 服务端向客户端推送消息技术之websocket的介绍
websocket的介绍 在讲解WebSocket前,我们先来看看下面这种场景,在HTTP协议下,怎么实现. 需求: 在网站中,要实现简单的聊天,这种情况怎么实现呢?如下图: 当发送私信的时候,如果要 ...
- java集成jpush实现客户端推送
代码地址如下:http://www.demodashi.com/demo/13700.html 前言 java 集成jpush 实现客户端推送 一.准备工作 开发环境: jdk1.6 Eclipse ...
- SuperSocket主动从服务器端推送数据到客户端
关键字: 主动推送, 推送数据, 客户端推送, 获取Session, 发送数据, 回话快照 通过Session对象发送数据到客户端 前面已经说过,AppSession 代表了一个逻辑的 socke ...
- 使用spring boot +WebSocket实现(后台主动)消息推送
言:使用此webscoket务必确保生产环境能兼容/支持!使用此webscoket务必确保生产环境能兼容/支持!使用此webscoket务必确保生产环境能兼容/支持!主要是tomcat的兼容与支持. ...
随机推荐
- 英特尔® 实感™ SDK 架构
英特尔® 实感™ SDK在架构上完全不同于其前代系统 — 英特尔® 感知计算 SDK. 如果您使用英特尔感知计算 SDK 进行应用开发,会很快发现,全新的 SDK 可提供增强型编程模式,从而可通过几种 ...
- php curl 的用法 转载
curl 是使用URL语法的传送文件工具,支持FTP.FTPS.HTTP HTPPS SCP SFTP TFTP TELNET DICT FILE和LDAP.curl 支持SSL证书.HTTP POS ...
- 理解C#系列 / 核心C# / 名称空间
名称空间namespace 名称空间 名称空间用来逻辑分类,而不是物理上的,名称空间与程序集无关[程序集:经由编译器编译得到的文件],同一个程序集中可以有2不同的名称空间,也可以在不同的程序集中定义同 ...
- idea基本
IntelliJ IDEA特色功能 IDEA所提倡的是智能编码,是减少程序员的工作,IDEA的特色功能有以下25点:智能的选取在很多时候我们要选取某个方法,或某个循环或想一步一步从一个变量到整个类慢慢 ...
- Vs2010搭建directshow 环境
一:材料 1, vs2010 2, winsdk7.1 http://www.microsoft.com/en-us/download/details.aspx?id=8442 更具自己电脑选择32 ...
- 基类和派生类--this
基类指针在程序运行的时候的确指向的是一个派生类的对象,但指针的类型仍然是基类指针.C++是一种强类型语言,因此不能用基类指针类型的指针直接调用派生类:而且,同一个类可能有多种不同的派生类,因此不知道实 ...
- scp实现mac与linux服务器之间文件传输
1.mac上传文件到linux服务器 scp 文件名 用户名@服务器ip:目标路径如:scp /Users/test/testFile test@xxx.xxx.xxx.xxx:/test/ 2.ma ...
- CentOS安全设置
删除多余的用户和用户组,修改口令文件属性,禁止[Ctrl+Alt+Delete]重启命令,防止别人ping的方法.整理自互联网. 1.删除多余的用户和用户组 //删除多余用户 # vi /etc/pa ...
- php读取excel日期类型数据的例子
提供一个读取的函数: 代码如下 复制代码 //excel日期转换函数function excelTime($date, $time = false) { if(function_exists('Gr ...
- sqlServer2008 手工注入
接着上一篇的<mysql手工注入> 参考:http://hi.baidu.com/ciqing_s/item/971bf994365130accc80e5ed http://hi.baid ...