【背景】javascript
今天,一個前端的師弟問我怎樣作實時聊天窗口,我堅決果斷地說:在前臺定時訪問服務端呀!師弟默默地百度了一番,最後告訴我,有一種技術是後服務端動推送信息給客戶端的,這種技術的名字叫comet,我驚呆了,由於徹底沒聽過,趕忙上網蒐集資料,耗了一個晚上寫了個簡單的例子,實現主動向客戶端發送信息。說是說主動,其實仍是要客戶端先獻出它的「第一次」,即只要它有先請求你一下,之後大家熟了,你想主動約它就約它!html
關於comet技術介紹及其實現原理,能夠參考網站 http://www.ibm.com/developerworks/cn/web/wa-lo-comet/ 的介紹。前端
簡單來講,就是客戶端發送請求到服務端,服務器端會阻塞請求直到有數據傳遞或超時才返回,以後客戶端 JavaScript 響應處理函數會在處理完服務器返回的信息後,再次發出請求,從新創建鏈接。當客戶端處理接收的數據、從新創建鏈接時,服務器端可能有新的數據到達;這些信息會被服務器端保存直到客戶端從新創建鏈接,客戶端會一次把當前服務器端全部的信息取回。 java
【工做環境】web
一、myeclipse2013apache
二、tomcat 6.0api
三、jdk 7瀏覽器
四、火狐瀏覽器緩存
說明: tomcat
測試成功的瀏覽器有:(1)火狐瀏覽器 (2)IE十、IE九、IE8 (3)360極速瀏覽器極速模式
測試失敗的瀏覽器有:(1)IE10兼容模式、IE7
【準備工做】
一、下載comet4j.js :http://files.cnblogs.com/xiaoMzjm/comet4j.js.rar
二、下載comet4j-tomcat6.jar :http://files.cnblogs.com/xiaoMzjm/comet4j-tomcat6.jar.rar
三、到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 , 監聽咱們本身的類。
【具體代碼(說明都寫在註釋裏面)】
一、web.xml
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>
二、java類TestComet
裏面附上了很多的註釋,若是想仔細研究建議看上面的賦予的API文檔連接。
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 }
三、客戶端代碼
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>
四、網頁顯示
數字1:2221
數字2:2321
能夠看出,兩個數字不停地每秒遞增。數字2比數字1 多了100,由於在服務端,number2的初始值爲100,number1的初始值爲0。
在瀏覽器上按F12,選擇netWork,以下圖,能夠看出,此鏈接從未斷開過。
有什麼寫錯或寫得很差的地方,歡迎你們提出來~