推送消息广播。 javascript
推送定向消息。 html
提供链接上线前、上线、下线前、下线、发送消息等多种可处理事件。 java
消息缓存机制,确保长轮询工做模式下不丢失消息。 web
客户端正常下线,服务端可当即感知。 apache
客户端异常中止工做,服务端可定时检查并感知。 编程
以注册通道应用的方式,让开发者对框架功能进行扩展,实现本身的应用。 浏览器
独立小巧,不依赖于第三方包。 缓存
与应用紧密集成,无需独立应用或服务器。 tomcat
与Session无关的链接机制,为开发人员提供最大程度的功能可控性。 服务器
面向事件编程,客户端与服务器端均为事件驱动开发模式,提供了良好的可扩展性机制。
各项性能参数都可配置。
支持多种主流浏览器,并支持Air应用环境。
Tomcat六、Tomcat7
支持XMLHTTPRequest对象的浏览器都可支持长轮询工做模式,但不必定可以支持长链接。
浏览器/平台 | 版本 | 长轮询 | 长链接 |
Internet Explorer | 6,7,8,9,10,11 | √ | X |
FireFox | 3.0+(更底版本未知) | √ | √ |
Chrome | 7.0+(更底版本未知) | √ | √ |
Safari | 5+(更底版本未知) | √ | √ |
Opera | 11.10+(更底版本未知) | √ | X |
Air | 1.5+(更底版本未知) | √ | √ |
IOS(Iphone/Ipad) | 3.1+(更底版本未知) | √ | √ |
Android | 未测试 | 未知 | 未知 |
BlackBerry | 未测试 | 未知 | 未知 |
使用方法
下载相关的jar包(根据本身使用的tomcat6仍是7选择)和相关js并放到本身项目当中
comet4j-tomcat6.jar comet4j-tomcat7.jar comet4j.js
Comet 流是按照长轮询的实现思路进一步发展的产物。令长轮询将事件通知发送回客户端后再也不关闭链接,而是一直保持直到超时事件发生才从新创建新的链接,这种变体咱们就称为 Comet 流。客户端可使用 XmlHttpRequest 对象中的 readyState 属性来判断是 Receiving 仍是 Loaded。Comet 流在服务端和客户端都须要维持一个比较长时间的链接状态,这一点在客户端不算什么太大的负担,可是服务端是要同时对多个客户端服务的,按照经典 Request-Response 交互模型,每个请求都占用一个 Web 线程不释放的话,Web 容器的线程则会很快消耗殆尽,而这些线程大部分时间处于空闲等待的状态。因此建议选择comet4j-tomcat7.jar ,由于Servlet 3.0的新特性异步处理只有在tomcat7.0及以上才支持,这样咱们Web 线程不须要同步的、一对一的处理客户端请求,能作到一个 Web 线程处理多个客户端请求。并且就算之后用HTML5的websocket也须要至少是tomcat7.0。
由于Comet4J工做在NIO方式下(自tomcat6.0后提供的Advanced NIO 技术以便一个 Servlet 线程能处理多个 Http Request),因此咱们须要调整服务器链接器配置,更换为NIO链接器。 打开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"/>
在web.xml中加载Comet4J框架
<listener> <listener-class>org.comet4j.core.CometAppListener</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>
客户端
<!DOCTYPE> <html> <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 kbDom = document.getElementById('kb'); JS.Engine.start('conn'); JS.Engine.on({ hello : function(kb){//侦听一个channel kbDom.innerHTML = kb; } }); JS.Engine.on( 'start', function(cId,channelList,engine){ alert('链接已创建,链接ID为:' + cId); }); } </script> </head> <body onload="init()"> 项目组成员:<span id="kb">...</span> </body> </html>
JS.Engine类是一个静态类,它负责服务器的链接与断开以及把服务器推过来的消息转化为事件分发。
JS.Engine.start(String str)和JS.Engine.stop(String str)分别控制链接和断开动做。
start方法须要传入一个字符串参数,用来指定您配置的Comet4J链接地址。好比按前面准备工做的配置了CometServlet的地址为/conn,那么链接就用:
JS.Engine.start('conn');
stop方法能够传参与不传参,传参为对断开链接的说明。
JS.Engine.stop(); JS.Engine.stop('主动断开');
JS.Engine.on方法来注册事件处理。当使用start方法成功创建链接已后JS.Engine会发出"start"事件,当断开后会发出“stop”事件,当收到某个通道推送过来的信息时也会发出与通道标识同名的事件。
JS.Engine.on({ hello : function(kb){//创建hello信道标识,当客户端对该信道推送消息时客户端就会接收并响应 kbDom.innerHTML = kb; } }); JS.Engine.on( 'start', function(cId,channelList,engine){ alert('链接已创建,链接ID为:' + cId); }); JS.Engine.on('stop',function(cause, cId, url, engine){ alert('链接已断开,链接ID为:' + cId + ',断开缘由:' + cause + ',断开的链接地址:'+ url); });
on方法注册事件可使用 on({name1:function(){...},name2:function(){...}})或者on('name',function(){...})两种方式。
特别注意:以上代码在事件处理函数中使用了alert仅为说明函数功能,实际使用中,在事件处理函数中切勿使用alert、prompt、confirm等能够中断脚本运行的函数,由于Engine须要实时的保持工做状态。
服务端
服务端由一个Jar包组成,其中最重的是CometContext和CometEngine两个类。
Comet Context 类
CometContext是一个单态类,经过其getInstance方法来得到实例,它主要负责框架的一些初始化工做保存着一些参数的配置值,除此以外它还有一个更重要的职责——负责注册应用通道标识。若是您想使用框架来实现本身的应用,那么您必须要为本身的应用分配一个惟一的通道标识,并将此通道标识在WEB容器启动时使用CometContext的registChannel方法进行注册,这样,客户端才能够正确接受此应用所推送的消息。
Comet Engine 类
CometContext类,它除了负责对链接的处理以外,对于开发人员而言,更加经常使用的多是它所提供的sendTo或sendToAll方法来向客户端发送消息。sendTo方法是将消息推送给全部指定信道的客户端,而sendToAll方法是将消息推送给指定信道的一个或多个链接ID的客户端。
String channel = "hello"; String someConnectionId = "1125-6634-888"; engine.sendToAll(channel , "我来了!"); engine.sendTo(channel , engine.getConnection(someConnectionId),“Hi,我是XXX”);
CometEngine另一个很重要的地方在于,它是框架工做的事件引擎的集散地,它提供了BeforeConnectEvent、BeforeDropEvent、ConnectEvent、DropEvent、MessageEvent等事件。经过对这些事件的处理来实现具体的功能:
class JoinListener extends ConnectListener { @Override public boolean handleEvent(ConnectEvent anEvent) { CometConnection conn = anEvent.getConn(); CometContext.getInstance().getEngine().sendTo("hello", conn.getId(),"欢迎上线"); } } CometEngine engine = CometContext.getInstance().getEngine(); engine.addConnectListener(new JoinListener());
测试代码:
class HelloWorld implements ServletContextListener { //定义信道标识 private static final String CHANNEL = "hello"; public void contextInitialized(ServletContextEvent arg0) { //获取CometContext实例 CometContext cc = CometContext.getInstance(); 注册hello信道 cc.registChannel(CHANNEL); //模拟推送 开启线程 Thread helloAppModule = new Thread(new HelloAppModule(), "Sender App Module"); //设置为守护线程 helloAppModule.setDaemon(true); helloAppModule.start(); } class HelloAppModule implements Runnable { public void run() { while (true) { try { //线程休眠模拟推送 Thread.sleep(1000); } catch (Exception ex) { ex.printStackTrace(); } CometEngine engine = CometContext.getInstance().getEngine(); engine.sendToAll(CHANNEL, getName()); } } } public String getName(){ String[]names = new String[]{"冯春雷","吴兆元","夏胜安","李瑞东","田东东","张文良","刘权","邵帅","肖小良","任银","王继伟"}; int number = new Random().nextInt(10) + 1; return names[number]; } public void contextDestroyed(ServletContextEvent arg0) { } }
运行项目代码:
成功!!!