Comet模式是一種服務器端推技術,它的核心思想提供一種能讓當服務器端往客戶端發送數據的方式。Comet模式爲何會出現?剛開始人們在客戶端經過不斷自動刷新整個頁面來更新數據,後來以爲體驗很差又使用了AJAX不斷從客戶端輪詢服務器更新數據,而後是使用Comet模式由服務器端經過長鏈接推數據。Comet模式能大大減小發送到服務器端的請求從而避免了不少開銷,並且它還具有更好的實時性。javascript
如圖所示,客戶端發送一個請求到服務器,服務器接收了鏈接後一直保持住鏈接不關閉;接着客戶端發送一個操做報文告訴服務器須要作什麼操做,服務器處理完事件1後會給客戶端響應,而後處理完事件2後又會給客戶端響應;而後客戶端繼續發送操做報文給服務器,服務器再進行響應。java
通常Comet模式須要NIO配合,而在BIO中沒法使用Comet模式。在Tomcat內部集成Comet模式的思路也比較清晰,引入了一個CometProcessor接口,此接口只有一個event方法,具體接口代碼以下:服務器
public interface CometProcessor extends Servlet{
public void event(CometEvent event)
throws IOException, ServletException;
}複製代碼
而CometEvent則表示Comet相關的事件,它包含四BEGIN, READ, END, ERROR四個事件,分別表示:
① BEGIN,表示請求開始,此時客戶端鏈接已被接收。
② READ,表示能夠讀取客戶端鏈接,你能夠開始讀取數據了,讀取的過程不會阻塞。
③ END,表示請求結束,此時客戶端鏈接將被斷開。
④ ERROR,表示發生了IO異常,通常將會結束這次請求而且鏈接會被斷開。app
下面看一個簡單的例子:ui
public class CometServlet extends HttpServlet implements CometProcessor {
protected ArrayList connections = new ArrayList();
public void event(CometEvent event) throws IOException, ServletException {
HttpServletRequest request = event.getHttpServletRequest();
HttpServletResponse response = event.getHttpServletResponse();
if (event.getEventType() == CometEvent.EventType.BEGIN) {
synchronized (connections) {
connections.add(response);
}
} else if (event.getEventType() == CometEvent.EventType.ERROR) {
synchronized (connections) {
connections.remove(response);
}
}else if (event.getEventType() == CometEvent.EventType.END) {
synchronized (connections) {
connections.remove(response);
}
} else if (event.getEventType() == CometEvent.EventType.READ) {
InputStream is = request.getInputStream();
byte[] buf = new byte[512];
do {
int n = is.read(buf);
if (n > 0) {
System.out.println(new String(buf, 0, n));
} else if (n < 0) {
return;
}
} while (is.available() > 0);
}
}
}複製代碼
這個例子中只是簡單的客戶端鏈接都接收起來而不作任何處理,並將客戶端發送過來的數據輸出。很容易理解,在BEGIN事件中接收鏈接並把響應對象假如到列表中,發送ERROR或END事件時則將響應對象移除,當READ事件時則讀取數據並輸出。spa
有了CometProcessor接口後,Tomcat內部就能夠識別Comet模式的Servlet了,咱們知道Tomcat對請求的處理是管道模式的,因此在Wrapper容器的管道中判斷加載的Servlet是否繼承了CometProcessor,繼承則說明是Comet模式,則使用Comet方式處理。它的處理過程如圖,當一個客戶端鏈接到來,被接收器接收後註冊到NioChannel隊列中,Poller組件不斷輪詢是否有NioChannel須要處理,若是有則調用前面實例化的Comet模式Servlet,這裏主要用到CometProcessor接口的event方法,Poller會將對應的請求對象、響應對象和事件封裝成都CometEvent對象並傳入event方法。此時即執行event方法的邏輯,完成對不一樣事件的處理,從而實現了Comet模式。
code
歡迎關注:cdn