本文轉自http://www.ibm.com/developerworks/cn/java/j-lo-WebSocket/
HTML5作為下一代WEB標准,擁有許多引人注目的新特性,如Canvas、本地存儲、多媒體編程接口、WebSocket 等等。本文認識WebSocket理論部分主要介紹HTML5 WebSocket的由來和運行機制。在《認識WebSocket應用篇》會重點介紹服務端(基於Tomcat)及客戶端(基於浏覽器原生 HTML5 API)實現的詳細步驟,並通過實際客戶案例描述了客戶端如何在 WebSocket 架構下使用 HTTP 長連接與服務器實現實時通信及消息推送的功能。
一、WebSocket技術的誕生背景
在web應用中,其交互過程是客戶端通過浏覽器向服務器發出一個請求,服務器接收到請求後進行處理然後將結果返回給浏覽器,浏覽器解析結果並呈現信息給用戶。隨著互聯網的快速發展,這種交互過程對於實時要求高、海量並發的Web應用有些力不從心。高並發與用戶實時響應是 Web 應用經常面臨的問題,這些應用常見的主要由社交網絡的即時通訊、Web導航應用中的地理位置獲取、金融證券的實時信息等。傳統的請求-響應模式的Web開發處理這個問題時,通常采用的方案有:
上述方式其實並不是真正的實時技術,只是使用了一種技巧來實現的模擬實時。在每次客戶端和服務器端交互的時候都是一次 HTTP 的請求和應答的過程,而每一次的 HTTP 請求和應答都帶有完整的 HTTP 頭信息,這就增加了每次傳輸的數據量。但這些方式最痛苦的是開發人員,因為不論客戶端還是服務器端的實現都很復雜,為了模擬比較真實的實時效果,開發人員 往往需要構造兩個HTTP連接來模擬客戶端和服務器之間的雙向通訊,一個連接用來處理客戶端到服務器端的數據傳輸,一個連接用來處理服務器端到客戶端的數據傳輸,這不可避免地增加了編程實現的復雜度,也增加了服務器端的負載,制約了應用系統的擴展性。
以上方式處理這些處理高並發及實時性需求的時候,會遇到難以逾越的瓶頸,需要的是一種高效節能的雙向通信機制來保證數據的實時傳輸。在此背景下,基於 HTML5 規范的、有 Web TCP 之稱的 WebSocket 應運而生。
早期 HTML5 並沒有形成業界統一的規范,各個浏覽器和應用服務器廠商有著各異的類似實現,如 IBM 的 MQTT,Comet 開源框架等,直到 2014 年,HTML5 在 IBM、微軟、Google 等巨頭的推動和協作下正式從草案落實為實際標准規范,各個應用服務器及浏覽器廠商逐步開始統一,在 JavaEE7 中也實現了 WebSocket 協議,從而無論是客戶端還是服務端的 WebSocket 都已完備,可以查閱HTML5 規范獲得最新的 HTML 協議規范及 WebSocket 支持。
二、WebSocket運行機制
WebSocket 是 HTML5 一種新的協議。本質是先通過HTTP/HTTPS協議進行握手後創建一個用於交換數據的TCP連接,它實現了浏覽器與服務器全雙工通信,能更好的節省服務器資源和帶寬並達到實時通訊,它建立在 TCP 之上,同 HTTP 一樣通過 TCP 來傳輸數據,但是它和 HTTP 存在不同,這主要包括兩個方面,一是WebSocket 是一種雙向通信協議,在建立連接後,WebSocket 服務器和 Browser/Client Agent 都能主動的向對方發送或接收數據,就像 Socket 一樣;二是WebSocket 需要類似 TCP 的客戶端和服務器端通過握手連接,連接成功後才能相互通信,下面左圖是傳統HTTP響應客戶端服務器交互圖,右圖是WebSocket 模式客戶端與服務器的交互圖。
由上,相對於傳統 HTTP 每次請求-應答都需要客戶端與服務端建立連接的模式,WebSocket 是類似 Socket 的 TCP 長連接的通訊模式,一旦 WebSocket 連接建立後,後續數據都以幀序列的形式傳輸。在客戶端斷開 WebSocket 連接或 Server 端斷掉連接前,不需要客戶端和服務端重新發起連接請求。在海量並發及客戶端與服務器交互負載流量大的情況下,極大的節省了網絡帶寬資源的消耗,且客戶端發送和接受消息是在同一個持久連接上發起,實時性強。
客戶端和服務端交互的報文方面WebSocket 通訊與傳統 HTTP 也是不同的。在客戶端,new WebSocket 實例化一個新的 WebSocket 客戶端對象,連接類似 ws://ip:port/path 的服務端 WebSocket URL,WebSocket 客戶端對象會自動解析並識別為 WebSocket 請求,從而連接服務端端口,執行雙方握手過程,客戶端發送數據格式類似:
WebSocket客戶端連接報文:
GET /webfin/websocket/ HTTP/1.1 Host: localhost Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg== Origin: http://localhost:8080 Sec-WebSocket-Version: 13
客戶端發起的 WebSocket 連接報文類似傳統 HTTP 報文,”Upgrade:websocket”參數值表明這是 WebSocket 類型請求,這個請求的目的就是要將客戶端和服務器端的通訊協議從 HTTP 協議升級到 WebSocket 協議。“Sec-WebSocket-Key”是 WebSocket 客戶端發送的一個 base64 編碼的密文,要求服務端必須返回一個對應加密的“Sec-WebSocket-Accept”應答,否則客戶端會拋出“Error during WebSocket handshake”錯誤,並關閉連接。
服務端收到報文後返回的數據格式類似:
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=
"Sec-WebSocket-Accept”的值是服務端采用與客戶端一致的密鑰計算出來後返回客戶端的,“HTTP/1.1 101 Switching Protocols”表示服務端接受 WebSocket 協議的客戶端連接,經過這樣的請求-響應處理後,客戶端服務端的 WebSocket 連接握手成功, 後續就可以進行 TCP 通訊。在開發方面,WebSocket API 相對簡單,只需要實例化 WebSocket,創建連接,然後服務端和客戶端就可以相互發送和響應消息。
三、WebSocket實現
WebSocket 的實現分為客戶端和服務端兩部分,客戶端(通常為浏覽器)發出 WebSocket 連接請求,服務端響應,實現類似 TCP 握手的動作,從而在浏覽器客戶端和 WebSocket 服務端之間形成一條 HTTP 長連接快速通道。兩者之間後續進行直接的數據互相傳送,不再需要發起連接和相應。
WebSocket 服務端在各個主流應用服務器廠商中已基本獲得符合 JEE JSR356 標准規范 API 的支持(詳見JSR356 WebSocket API 規范),以下列舉了部分常見的商用及開源應用服務器對 WebSocket Server 端的支持情況:
服務器端需要我們自己來實現,目前市場上開源的實現也比較多。如:
WebSocket客戶端API
對於 WebSocket 客戶端,主流的浏覽器(包括 PC 和移動終端)現已都支持標准的 HTML5 的 WebSocket API,這意味著客戶端的 WebSocket JavaScirpt 腳本具備良好的一致性和跨平台特性,以下列舉了常見的浏覽器廠商對 WebSocket 的支持情況:
客戶端 WebSocket API 基本上已經在各個主流浏覽器廠商中實現了統一,因此使用標准 HTML5 定義的 WebSocket 客戶端的 JavaScript API 即可,當然也可以使用業界滿足 WebSocket 標准規范的開源框架,如 Socket.io。