即時Web通信在一些對數據實時性要求特別嚴格的應用中十分重要,如監控系統、報價系統、股票交易系統和即時在線聊天應用等,由於http協議設計當初是為了服務器端響應客戶端的請求而設計的,只能在客戶端主動發送請求后進行處理然后返回結果。為了實現上述各種即時應用的功能,出現了一系列“Hack”的手段來模擬實現服務器端主動推送信息的功能,也就是模擬了服務器和客戶端直接全雙工的通信。這樣主要考慮的是如下問題:
- 客戶端如何接收、處理信息,是否需要使用套接口或是使用遠程調用。客戶端呈現給用戶的是 HTML 頁面還是 Java applet 或 Flash 窗口。如果使用套接口和遠程調用,怎么和 JavaScript 結合修改 HTML 的顯示。
- 客戶與服務器端通信的信息格式,采取怎樣的出錯處理機制。
- 客戶端是否需要支持不同類型的瀏覽器如 IE、Firefox,是否需要同時支持 Windows 和 Linux 平台。
與此同時,HTML5中websocket的出現作為新一代實現真正服務器與客戶端全雙工連接的方式,是目前以及今后開發實時Web應用的主要實現方法。
一、基於客戶端套接口的實現
1、Java Applet
客戶端瀏覽器安裝java插件后,通過將java applet嵌入到html頁面中,通過java.net.Socekt或者java.net.DatagramSocekt或者java.net.MulticastSocket建立與服務器端的套接字接口連接,這是建立的原始的TCP套接字來實現服務器主動推送消息。其不足指出是客戶端收到服務器端返回的信息后無法通過javascript更新html頁面的內容。這種方法是1996年最早在Netscape2.0瀏覽器中實現的。
2、Flash XML Socket
客戶端瀏覽器安裝Flash插件后,利用Flash提供的XMLSocket類來建立socket連接。同時javascript與Flash聯系緊密,在javascript中可以直接調用Flash程序提供的接口。
具體方法是在頁面嵌入使用XMLSocket類的Flash程序,javascript通過調用Flash提供的套接口接口與服務器端套接口通信,javascript收到以XML格式返回的信息后可以很容易控制和修改hml頁面的內容,因此這種方式在目前的很多應用中依然廣泛使用。但是使用套接口需要設置通信端口,可能受到防火牆或者代理服務器的端口限制,同時必須要安裝Flash插件才能使用。
二、Comet模型
Comet是一種實現Web推送的編程模型,能使服務器主動將變化的數據發送到客戶端而無需客戶端發送請求。在2001年最早使用了建立兩個http socket連接的方式來實現,是基於J2SE的一個web服務器。在2006年Alex Russell在其個人博客中發表了comet這個概念,此時使用Ajax方式來實現。Comet翻譯為中文就是“彗星”,用在這里就是指客戶端與服務器端建立連接后,會像彗星托着長長的尾巴一樣一直保持連接,從而就可以實現服務器主動發送數據到客戶端的即時要求。總結起來,基於comet模型的實現方式概括為以下兩種:Streaming和Polling。
1、Streaming
使用基於iframe的html頁面標記,通過在html頁面嵌入一個隱藏幀,將其的src屬性設置為對一個長連接的請求,這樣服務器端就可以不斷往客戶端輸入數據。
服務器端返回的數據不是具體在頁面顯示的html文檔內容,而是返回對客戶端javascript函數調用的javascript代碼,類似於:
- <script type="text/javascript">js_func("data from server");</script>
ifream收到這樣的script代碼后寫入到頁面,瀏覽器的javascript引擎執行這些javascript代碼,就達到了服務器推送的目的。其中服務器端代碼需要做特殊處理,使用一個無限循環保持這個連接,每次循環flush內容,然后sleep一段時間后進入下一次循環。
這種方式的優點是在絕大多數瀏覽器都支持,不足在於缺乏一種有效的錯誤處理機制,還有就是跟蹤推送中間過程的不同狀態基本是不可能的,同時必須配合非阻塞的服務器才能使用,否則多人訪問同一頁面將服務器IO占滿之后就不能訪問了。
2、Polling
自從有了Ajax以后,通過使用javascript代碼調用XMLHttpRequest對象在客戶端發送http請求就得以實現。與基於插件形式實現的不同的是:
- 服務器端會阻塞請求直到有數據傳遞或超時才返回。
- 客戶端 JavaScript 響應處理函數會在處理完服務器返回的信息后,再次發出請求,重新建立連接。
- 當客戶端處理接收的數據、重新建立連接時,服務器端可能有新的數據到達;這些信息會被服務器端保存直到客戶端重新建立連接,客戶端會一次把當前服務器端所有的信息取回。
三、Websocket
HTML5提供了Websocket,定義了一個全雙工通信的信道,這不僅僅是對常規HTTP通信的一種增量,同時是一個巨大進步,對即時的、事件驅動的Web程序的實現提供了無線的開發空間。
使用輪詢時,由於實時數據不可測,因此不能避免有不必要的請求,這樣在低消息率情況下會有很多無用的連接不斷打開和關閉,浪費流量。
使用長輪詢時,服務器收到請求后在一段時間保持打開,在時間內服務器收到通知則發送響應,否則當時間到了的時候就終止打開的請求,但是當信息量很大的時候,與輪詢相比並沒有實質性的性能改善。
使用流解決方案時,瀏覽器發送請求后服務器會一直保持打開狀態,且是無限期或一段時間內都處於打開狀態。這樣當訪問量很大時,每個連接都會消耗服務器很多資源,對服務器端的壓力很大。同時由於流任然是封裝在http中,期間的防火牆和代理服務器可能對響應消息進行緩沖從而造成消息傳遞的時延。
同時,只要是基於http請求的凡事都會涉及http請求頭和響應頭,包含有大量不必要的數據,這樣大量耗費了網絡帶寬,而真正用於傳遞有效信息的數據可能只有幾個字節,得不償失。同時半雙工http基礎上模擬全雙工需要使用兩個連接,一個用於下行數據流,一個用於上行數據流。這樣兩個連接的協作也會造成大量的資源消耗。
綜合上述,websocket的出現就是為了解決上述所有解決方案的不足而設計的。websocket可以實現500:1甚至1000:1的http消息頭流量的縮減,同時實現3:1的通信延遲的縮減。同時實現起來簡單高效。
以上總結是對整個即時Web通信的概念性總結,個人總覺得對整體有個概念性總結后,就不會在具體實現的時候以致盲目,關於具體實現細節在見另外博文,同時各人實現起來的方式也會有所不同,願和大家一起交流學習。