服務器推送技術的基礎思想是將瀏覽器主動查詢信息改為服務器主動發送信息,服務器發送一批數據,瀏覽器顯示消息,同時保證與服務器的連接,當服務器需要再一次的發送數據,瀏覽器顯示數據并保持連接。
comet基于HTTP長連接技術,無需安裝插件。
?
?
?
- comet:一個概念,web push
- pushlet:comet的一個實現。
- 就是保持長連接的策略問題,有人用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()。來終止連接。
?
?
- 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:
![]() |
![]() |
![]() |
![]() |
CometEvent event.... event.setTimeout(30*1000); |
![]() |
![]() |
![]() |
![]() |
or
![]() |
![]() |
![]() |
![]() |
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代碼示例:

?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相關代碼:

?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不能正常獲得消息
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
