comet基於HTTP長鏈接技術(java即時通訊,推送技術詳解)

服務器推送技術的基礎思想是將瀏覽器主動查詢信息改成服務器主動發送信息,服務器發送一批數據,瀏覽器顯示消息,同時保證與服務器的鏈接,當服務器須要再一次的發送數據,瀏覽器顯示數據並保持鏈接。javascript

comet基於HTTP長鏈接技術,無需安裝插件。java

 

 

 

  • comet:一個概念,web push
  • pushlet:comet的一個實現。
  • comet4j:也是comet的一個實現(comet4j開發指南 googlecode
  • 就是保持長鏈接的策略問題,有人用jquery寫了相應的util

 

  • Pushlet基於HTTP流,這種技術經常用在多媒體視頻、通信應用中,好比QuickTime。與裝載HTTP頁面以後立刻關閉HTTP鏈接的作法相反,Pushlet採用HTTP流方式將新變更的數據主動地推送到client(客戶端),再此期間HTTP鏈接一直保持打開。有關如何在Java中實現這種Keep-alive的長鏈接請參看Sun提供的《HTTP Persistent Connection》和W3C的《HTTP1.1規範》

 

  • Tomcat的comet原理其實一樣很簡單,它無非就是作了一件事情,它容許servlet執行完畢後的response沒有被回收,咱們只要拿到這個Reponse的引用並保存起來,就能夠隨時從Server向Client端Push數據了。每一個鏈接一個線程的模型便很是簡單。該模型對於 Comet 不大適用,可是,Java 對此一樣有解決的辦法。爲了有效地處理 Comet,須要非阻塞 IO,Java 經過它的 NIO 庫提供非阻塞 IO。兩種最流行的開源服務器 Apache Tomcat 和 Jetty 都利用 NIO 增長非阻塞 IO,從而支持 Comet.

 

  • 而非阻塞I/O和同步I/O最明顯的不一樣就是同步I/O全部可能被阻塞的地址在非阻塞I/O中都不會被阻塞。如在讀取數據時,若是數據暫時沒法被讀取。那麼在非阻塞I/O中會馬上返回,以便程序能夠執行其餘的代碼,而後系統會不斷偵測這個未完成的讀取操做,直到能夠繼續讀數據時再來完成這個操做。非阻塞式IO的出現的目的就是爲了解決這個瓶頸。而非阻塞式IO是怎麼實現的呢?非阻塞IO處理鏈接的線程數和鏈接數沒有聯繫,也就是說處理10000個鏈接非阻塞IO不須要10000個線程,你能夠用1000個也能夠用2000個線程來處理。由於非阻塞IO處理鏈接是異步的。當某個鏈接發送請求到服務器,服務器把這個鏈接請求看成一個請求"事件",並把這個"事件"分配給相應的函數處理。咱們能夠把這個處理函數放到線程中去執行,執行完就把線程歸還。這樣一個線程就能夠異步的處理多個事件。而阻塞式IO的線程的大部分時間都浪費在等待請求上了。
  • 在comet中,爲了保持長鏈接,若是使用阻塞時IO,則不可避免的對每個鏈接保持一個線程。不一樣於短鏈接,線程能夠及時釋放。長鏈接對應的線程可能永遠不能釋放,這樣一個server可以服務的客戶端的數量就受到了線程數量上限的限制。而使用NIO能夠伺候多個鏈接而沒必要要保持相應數量的線程。就解決了這個問題。

 

  • Tomcat提供了CometProcessor接口,有這種特定標記的Servlet,Tomcat會作特殊處理,Tomcat不會把它當作普通Servlet實行完畢後,會回收request和response。注意:實現CometProcessor接口後不用在servlet中寫doGet,doPoset方法,全部事件在BEGIN,READ,END,ERROR中實現。
  • 從event拿到的request和response不會在begin和end/error之間不會被釋放,一直有效。能夠用來傳遞消息。Note that the response object and dependent OutputStream and Writer are still not synchronized, so when they are accessed by multiple threads, synchronization is mandatory.
  • BEGIN:初始化參數和獲取request和response,結束時,request is commited
  • READ(只有POST方法,纔會觸發該事件):有數據從request進來,能夠從request讀取數據。在此事件以外不容許讀取request的數據。On some platforms, like Windows, a client disconnect is indicated by a READ event. Reading from the stream may result in -1, an IOException or an EOFException. Make sure you properly handle all these three cases. If you don't catch the IOException, Tomcat will instantly invoke your event chain with an ERROR as it catches the error for you, and you will be notified of the error at that time.
  • END: End may be called to end the processing of the request. Fields that have been initialized in the begin method should be reset. After this event has been processed, the request and response objects, as well as all their dependent objects will be recycled and used to process other requests. End will also be called when data is available and the end of file is reached on the request input (this usually indicates the client has pipelined a request).
  • ERROR: Error will be called by the container in the case where an IO exception or a similar unrecoverable error occurs on the connection. Fields that have been initialized in the begin method should be reset. After this event has been processed, the request and response objects, as well as all their dependent objects will be recycled and used to process other requests.(END,ERROR以後request和response就不要再用了)

 

  • ventSubType.TIMEOUT: The connection timed out (sub type of ERROR); note that this ERROR type is not fatal, and the connection will not be closed unless the servlet uses the close method of the event.
  • EventSubType.CLIENT_DISCONNECT: The client connection was closed (sub type of ERROR). method of the event.
  • EventSubType.IOEXCEPTION: An IO exception occurred, such as invalid content, for example, an invalid chunk block (sub type of ERROR).
  • EventSubType.WEBAPP_RELOAD: The web application is being reloaded (sub type of END).
  • EventSubType.SESSION_END: The servlet ended the session (sub type of END).

BEGIN-READ-READ-Error/TIMEOUT。隨時能夠event.close()。來終止鏈接。jquery

 

 

  • writer.flush();writer.close();長輪詢和流風格的comet的差異只是取決因而否有第二句(長輪詢須要client端在response關閉後再重連)

 

If you are using the NIO connector, you can set individual timeouts for your different comet connections. To set a timeout, simply set a request attribute like the following code shows:web

CometEvent event.... event.setTimeout(30*1000);

orapache

event.getHttpServletRequest().setAttribute("org.apache.tomcat.comet.timeout", new Integer(30 * 1000));

This sets the timeout to 30 seconds. Important note, in order to set this timeout, it has to be done on the BEGIN event. The default value is soTimeout瀏覽器

 

 

      簡單的Comet servlet代碼示例:tomcat


 1 import java.io.*;
 2 import javax.servlet.ServletException;
 3 import javax.servlet.http.*;
 4 import org.apache.catalina.CometEvent;
 5 import org.apache.catalina.CometProcessor;
 6 import org.apache.catalina.CometEvent.EventType;
 7 
 8 public class cometServlet extends HttpServlet implements CometProcessor {
 9    
10         public void event(CometEvent e) throws IOException, ServletException {
11                if(e.getEventType() == EventType.BEGIN) {
12                       // fill in code handling here
13                    HttpServletResponse response = e.getHttpServletResponse();
14                    PrintWriter out = response.getWriter();
15                    out.write("Hello world");
16                    out.flush(); 
17                    //System.out.println("message sent");
18                }
19                if(e.getEventType() == EventType.READ) {
20                   // fill in code handling here
21                }
22                // and continue handing other events
23         }
24 }

在此源代碼中,僅完成向客戶端發送Hello World字符串的功能,關鍵點,out.flush()不可缺乏服務器

 

 

客戶端javascript相關代碼:session


 1 <script>
 2 function CometEx() {
 3   var request =  new XMLHttpRequest();
 4   request.open("GET", 'http://localhost:8080/cometEx/cometServlet', true);
 5   request.onreadystatechange = function() {
 6     if (request.readyState == 3 && request.status == 200) {
 7            alert(request.responseText);     
 8     }
 9   }
10   request.send(null);
11 }
12 </script>

 

服務器端代碼相似與普通Ajax代碼,其中,須要注意的是:request.readyState值若是設置爲4,瀏覽器會處於長期等待狀態,而收不到響應消息,設置爲3後,firefox瀏覽器正常,但IE不能正常得到消息app

相關文章
相關標籤/搜索