服務(wù)器推送技術(shù)的基礎(chǔ)思想是將瀏覽器主動(dòng)查詢信息改為服務(wù)器主動(dòng)發(fā)送信息,服務(wù)器發(fā)送一批數(shù)據(jù),瀏覽器顯示消息,同時(shí)保證與服務(wù)器的連接,當(dāng)服務(wù)器需要再一次的發(fā)送數(shù)據(jù),瀏覽器顯示數(shù)據(jù)并保持連接。
comet基于HTTP長連接技術(shù),無需安裝插件。
?
?
?
- comet:一個(gè)概念,web push
- pushlet:comet的一個(gè)實(shí)現(xiàn)。
- 就是保持長連接的策略問題,有人用jquery寫了相應(yīng)的util
?
- Pushlet基于HTTP流,這種技術(shù)常常用在多媒體視頻、通訊應(yīng)用中,比如QuickTime。與裝載HTTP頁面之后馬上關(guān)閉HTTP連接的做法相反,Pushlet采用HTTP流方式將新變動(dòng)的數(shù)據(jù)主動(dòng)地推送到client(客戶端),再此期間HTTP連接一直保持打開。有關(guān)如何在Java中實(shí)現(xiàn)這種Keep-alive的長連接請參看Sun提供的《HTTP Persistent Connection》和W3C的《HTTP1.1規(guī)范》
?
- Tomcat的comet原理其實(shí)同樣很簡單,它無非就是做了一件事情,它允許 servlet 執(zhí)行完畢后的response沒有被回收,我們只要拿到這個(gè)Reponse的引用并保存起來,就可以隨時(shí)從Server向Client端Push 數(shù)據(jù) 了。每個(gè)連接一個(gè)線程的模型便非常簡單。該模型對于 Comet 不大適用,但是,Java 對此同樣有解決的辦法。為了有效地處理 Comet,需要非阻塞 IO,Java 通過它的 NIO 庫提供非阻塞 IO。兩種最流行的開源服務(wù)器 Apache Tomcat 和 Jetty 都利用 NIO 增加非阻塞 IO,從而支持 Comet.
?
- 而非阻塞I/O和同步I/O最明顯的不同就是同步I/O所有可能被阻塞的地址在非阻塞I/O中都不會被阻塞。如在讀取數(shù)據(jù)時(shí),如果數(shù)據(jù)暫時(shí)無法被讀取。那么在非阻塞I/O中會立刻返回,以便程序可以執(zhí)行其他的代碼,然后系統(tǒng)會不斷偵測這個(gè)未完成的讀取操作,直到可以繼續(xù)讀數(shù)據(jù)時(shí)再來完成這個(gè)操作。非阻塞式IO的出現(xiàn)的目的就是為了解決這個(gè)瓶頸。而非阻塞式IO是怎么實(shí)現(xiàn)的呢?非阻塞IO處理連接的線程數(shù)和連接數(shù)沒有聯(lián)系,也就是說處理10000個(gè)連接非阻塞IO不需要10000個(gè)線程,你可以用1000個(gè)也可以用2000個(gè)線程來處理。因?yàn)榉亲枞鸌O處理連接是異步的。當(dāng)某個(gè)連接發(fā)送請求到服務(wù)器,服務(wù)器把這個(gè)連接請求當(dāng)作一個(gè)請求"事件",并把這個(gè)"事件"分配給相應(yīng)的函數(shù)處理。我們可以把這個(gè)處理函數(shù)放到線程中去執(zhí)行,執(zhí)行完就把線程歸還。這樣一個(gè)線程就可以異步的處理多個(gè)事件。而阻塞式IO的線程的大部分時(shí)間都浪費(fèi)在等待請求上了。
- 在comet中,為了保持長連接,如果使用阻塞時(shí)IO,則不可避免的對每一個(gè)連接保持一個(gè)線程。不同于短連接,線程可以及時(shí)釋放。長連接對應(yīng)的線程可能永遠(yuǎn)不能釋放,這樣一個(gè)server能夠服務(wù)的客戶端的數(shù)量就受到了線程數(shù)量上限的限制。而使用NIO可以伺候多個(gè)連接而不必要保持相應(yīng)數(shù)量的線程。就解決了這個(gè)問題。
?
- Tomcat提供了CometProcessor接口,有這種特定標(biāo)記的Servlet,Tomcat會做特殊處理,Tomcat不會把它當(dāng)做普通Servlet實(shí)行完畢后,會回收request和response。注意:實(shí)現(xiàn)CometProcessor接口后不用在servlet中寫doGet,doPoset方法,所有事件在BEGIN,READ,END,ERROR中實(shí)現(xiàn)。
- 從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:初始化參數(shù)和獲取request和response,結(jié)束時(shí),request is commited
- READ(只有POST方法,才會觸發(fā)該事件):有數(shù)據(jù)從request進(jìn)來,可以從request讀取數(shù)據(jù)。在此事件之外不允許讀取request的數(shù)據(jù)。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。隨時(shí)可以event.close()。來終止連接。
?
?
- writer.flush(); writer.close();長輪詢和流風(fēng)格的comet的差別只是取決于是否有第二句(長輪詢需要client端在response關(guān)閉后再重連)
?
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?}
在此源代碼中,僅完成向客戶端發(fā)送Hello World字符串的功能,關(guān)鍵點(diǎn),out.flush()不可缺少
?
?
客戶端javascript相關(guān)代碼:

?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>
?
服務(wù)器端代碼類似與普通Ajax代碼,其中,需要注意的是:request.readyState值如果設(shè)置為4,瀏覽器會處于長期等待狀態(tài),而收不到響應(yīng)消息,設(shè)置為3后,firefox瀏覽器正常,但I(xiàn)E不能正常獲得消息
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

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