WebSocket 協議本質上是一個基於 TCP 的協議。爲了創建一個 WebSocket 鏈接,客戶端瀏覽器首先要向服務器發起一個 HTTP 請求,這個請求和一般的 HTTP 請求不一樣,包含了一些附加頭信息,其中附加頭信息」Upgrade: WebSocket」表 明這是一個申請協議升級的 HTTP 請求,服務器端解析這些附加的頭信息而後產生應答信息返回給客戶端,客戶端和服務器端的 WebSocket 鏈接就創建起來了,雙方就能夠經過這個鏈接通道自由的傳遞信息,而且這個鏈接會持續存在直到客戶端或者服務器端的某一方主動的關閉鏈接。node
下面咱們來詳細介紹一下 WebSocket 規範,因爲這個規範目前仍是處於草案階段,版本的變化比較快,咱們選擇 draft-hixie-thewebsocketprotocol-76版原本描述 WebSocket 協議。由於這個版本目前在一些主流的瀏覽器上好比 Chrome,、FireFox、Opera 上都獲得比較好的支持,您若是參照的是新一些的版本話,內容可能會略有差異。git
一個典型的 WebSocket 發起請求和獲得響應的例子看起來以下:web
清單 1. WebSocket 握手協議算法
客戶端到服務端: GET /demo HTTP/1.1 Host: example.com Connection: Upgrade Sec-WebSocket-Key2: 12998 5 Y3 1 .P00 Upgrade: WebSocket Sec-WebSocket-Key1: 4@1 46546xW%0l 1 5 Origin: http://example.com [8-byte security key] 服務端到客戶端: HTTP/1.1 101 WebSocket Protocol Handshake Upgrade: WebSocket Connection: Upgrade WebSocket-Origin: http://example.com WebSocket-Location: ws://example.com/demo [16-byte hash response]
這些請求和一般的 HTTP 請求很類似,可是其中有些內容是和 WebSocket 協議密切相關的。咱們須要簡單介紹一下這些請求和應答信息,」Upgrade:WebSocket」表示這是一個特殊的 HTTP 請求,請求的目的就是要將客戶端和服務器端的通信協議從 HTTP 協議升級到 WebSocket 協議。從客戶端到服務器端請求的信息裏包含有」Sec-WebSocket-Key1」、「Sec-WebSocket-Key2」和」[8-byte securitykey]」這樣的頭信息。這是客戶端瀏覽器須要向服務器端提供的握手信息,服務器端解析這些頭信息,並在握手的過程當中依據這些信息生成一 個 16 位的安全密鑰並返回給客戶端,以代表服務器端獲取了客戶端的請求,贊成建立 WebSocket 鏈接。一旦鏈接創建,客戶端和服務器端就能夠經過這個通道雙向傳輸數據了。編程
在實際的開發過程當中,爲了使用 WebSocket 接口構建 Web 應用,咱們首先須要構建一個實現了 WebSocket 規範的服務器,服務器端的實現不受平臺和開發語言的限制,只須要聽從 WebSocket 規範便可,目前已經出現了一些比較成熟的 WebSocket 服務器端實現,好比:數組
若是以上的 WebSocket 服務端實現還不能知足您的業務需求的話,開發人員徹底能夠根據 WebSocket 規範本身實現一個服務器。在「WebSocket 實戰」這一節,咱們將使用 Microsoft .NET 平臺上的 C# 語言來打造一個簡單的 WebSocket 服務器,繼而構建一個簡單的實時聊天系統。xcode
上一節介紹了 WebSocket 規範,其中主要介紹了 WebSocket 的握手協議。握手協議一般是咱們在構建 WebSocket 服務器端的實現和提供瀏覽器的 WebSocket 支持時須要考慮的問題,而針對 Web 開發人員的 WebSocket JavaScript 客戶端接口是很是簡單的,如下是 WebSocket JavaScript 接口的定義:瀏覽器
清單 2. WebSocket JavaScript 定義安全
JavaScript
代碼
其中 URL 屬性表明 WebSocket 服務器的網絡地址,協議一般是」ws」,send 方法就是發送數據到服務器端,close 方法就是關閉鏈接。除了這些方法,還有一些很重要的事件:onopen,onmessage,onerror 以及 onclose。咱們借用 Nettuts 網站上的一張圖來形象的展現一下 WebSocket 接口:服務器
圖 2. WebSocket JavaScript 接口
下面是一段簡單的 JavaScript 代碼展現了怎樣創建 WebSocket 鏈接和獲取數據:
清單 3. 創建 WebSocket 鏈接的實例 JavaScript 代碼
JavaScript
代碼
下面是主流瀏覽器對 HTML5 WebSocket 的支持狀況:
瀏覽器 | 支持狀況 |
---|---|
Chrome | Supported in version 4+ |
Firefox | Supported in version 4+ |
Internet Explorer | Supported in version 10+ |
Opera | Supported in version 10+ |
Safari | Supported in version 5+ |
這一節裏咱們用一個案例來演示怎麼使用 WebSocket 構建一個實時的 Web 應用。這是一個簡單的實時多人聊天系統,包括客戶端和服務端的實現。客戶端經過瀏覽器向聊天服務器發起請求,服務器端解析客戶端發出的握手請求併產生應答 信息返回給客戶端,從而在客戶端和服務器之間創建鏈接通道。服務器支持廣播功能,每一個聊天用戶發送的信息會實時的發送給全部的用戶,當用戶退出聊天室時, 服務器端須要清理相應用戶的鏈接信息,避免資源的泄漏。如下咱們分別從服務器端和客戶端來演示這個 Web 聊天系統的實現,在實現方式上咱們採用了 C# 語言來實現 WebSocket 服務器,而客戶端是一個運行在瀏覽器裏的 HTML 文件。
這個聊天服務器的實現和基於套接字的網絡應用程序很是相似,首先是服務器端要啓動一個套接字監聽來自客戶端的鏈接請求,關鍵的區別在於 WebSocket 服務器須要解析客戶端的 WebSocket 握手信息,並根據 WebSocket 規範的要求產生相應的應答信息。一旦 WebSocket 鏈接通道創建之後,客戶端和服務器端的交互就和普通的套接字網絡應用程序是同樣的了。因此在下面的關於 WebSocket 服務器端實現的描述中,咱們主要闡述 WebSocket 服務器怎樣處理 WebSocket 握手信息,至於 WebSocket 監聽端口的創建,套接字信息流的讀取和寫入,都是一些經常使用的套接字編程的方式,咱們就很少作解釋了,您能夠自行參閱本文的附件源代碼文件。
在描述 WebSocket 規範時提到,一個典型的 WebSocket Upgrade 信息以下所示:
GET /demo HTTP/1.1 Host: example.com Connection: Upgrade Sec-WebSocket-Key2: 12998 5 Y3 1 .P00 Upgrade: WebSocket Sec-WebSocket-Key1: 4@1 46546xW%0l 1 5 Origin: http://example.com [8-byte security key]
其中 Sec-WebSocket-Key1,Sec-WebSocket-Key2 和 [8-byte security key] 這幾個頭信息是 WebSocket 服務器用來生成應答信息的來源,依據 draft-hixie-thewebsocketprotocol-76 草案的定義,WebSocket 服務器基於如下的算法來產生正確的應答信息:
至此,客戶端和服務器的 WebSocket 握手就完成了,WebSocket 通道也創建起來了。下面首先介紹一下服務器端實現是如何根據用戶傳遞的握手信息來生成網絡字節數組的。.NET 平臺提供了很方便的對字符串,數值以及數組操做的函數,因此生成字節數組的方法仍是很是簡單明瞭的,代碼以下:
清單 4. 生成網絡字節數組的代碼
獲得網絡字節數組之後,服務器端生成 16 位安全密鑰的方法以下所示:
C#
代碼
清單 5. 生成 16 位安全密鑰的代碼
C#
代碼
整個實現是很是簡單明瞭的,就是將生成的網絡字節數組和客戶端提交的頭信息裏的 [8-byte security key] 合併成一個 16 位字節數組並用 MD5 算法加密,而後將生成的安全密鑰做爲應答信息返回給客戶端,雙方的 WebSocekt 鏈接通道就創建起來了。實現了 WebSocket 握手信息的處理邏輯,一個具備基本功能的 WebSocket 服務器就完成了。整個 WebSocket 服務器由兩個核心類構成,一個是 WebSocketServer,另一個是 SocketConnection,出於篇幅的考慮,咱們不介紹每一個類的屬性和方法了,文章的附件會給出詳細的源代碼,有興趣的讀者能夠參考。
服務器剛啓動時的畫面以下:
圖 3. WebSocket 服務器剛啓動的畫面
客戶端能夠依據這個信息填寫聊天服務器的鏈接地址,當有客戶端鏈接到聊天服務器上時,服務器會打印出客戶端和服務器的握手信息,每一個客戶的聊天信息也會顯示在服務器的界面上,運行中的聊天服務器的界面以下:
圖 4. 有客戶端鏈接到 WebSocket 服務器的
以上咱們簡單描述了實現一個 WebSocket 服務器的最基本的要素,下一節咱們會描述客戶端的實現。
客戶端的實現相對於服務器端的實現來講要簡單得多了,咱們只須要發揮想象去設計 HTML 用戶界面,而後呼叫 WebSocket JavaScript 接口來和 WebSocket 服務器端來交互就能夠了。固然別忘了使用一個支持 HTML5 和 WebSocket 的瀏覽器,在筆者寫這篇文章的時候使用的瀏覽器是 Firefox。客戶端的頁面結構是很是簡潔的,初始運行界面以下:
圖 5. 聊天室客戶端初始頁面
當頁面初次加載的時候,首先會檢測當前的瀏覽器是否支持 WebSocket 並給出相應的提示信息。用戶按下鏈接按鈕時,頁面會初始化一個到聊天服務器的 WebSocekt 鏈接,初始化成功之後,頁面會加載對應的 WebSocket 事件處理函數,客戶端 JavaScript 代碼以下所示:
清單 6. 初始化客戶端 WebSocket 對象的代碼
JavaScript
代碼
當用戶按下發送按鈕,客戶端會調用WebSocket對象向服務器發送信息,而且這個消息會廣播給全部的用戶,實現代碼以下所示:
JavaScript
代碼
若是有多個用戶登陸到聊天服務器,客戶端頁面的運行效果以下所示:
圖 6. 聊天客戶端運行頁面
至此咱們已經完成了一個完整的 WebSocket 客戶端實現,用戶能夠體驗一下這個聊天室的簡單和快捷,徹底不用考慮頁面的刷新和繁瑣的 Ajax 調用,享受桌面程序的用戶體驗。WebSocket 的強大和易用可見一斑,您徹底能夠在這個基礎上加入更多的功能,設計更加漂亮的用戶界面,切身體驗 WebSocket 的震撼力。完整的客戶端代碼請參閱附件提供的源代碼。
WebSocket 的優勢已經列舉得不少了,可是做爲一個正在演變中的 Web 規範,咱們也要看到目前用 Websocket 構建應用程序的一些風險。首先,WebSocket 規範目前還處於草案階段,也就是它的規範和 API 仍是有變更的可能,另外的一個風險就是微軟的 IE 做爲佔市場份額最大的瀏覽器,和其餘的主流瀏覽器相比,對 HTML5 的支持是比較差的,這是咱們在構建企業級的 Web 應用的時候必需要考慮的一個問題。
本文介紹了 HTML5 WebSocket 的橫空出世以及它嘗試解決的的問題,而後介紹了 WebSocket 規範和 WebSocket 接口,以及和傳統的實時技術相比在性能上的優點,而且演示了怎樣使用 WebSocket 構建一個實時的 Web 應用,最後咱們介紹了當前的主流瀏覽器對 HTML5 的支持狀況和 WebSocket 的侷限性。不過,咱們應該看到,儘管 HTML5 WebSocket 目前還有一些侷限性,可是已是大勢所趨,微軟也明確表達了將來對 HTML5 的支持,並且這些支持咱們能夠在 Windows 8 和 IE10 裏看到,咱們也在各類移動設備,平板電腦上看到了 HTML5 和 WebSocket 的身影。WebSocket 將會成爲將來開發實時 Web 應用的生力軍應該是毫無懸念的了,做爲 Web 開發人員,關注 HTML5,關注 WebSocket 也應該提上日程了,不然咱們在新一輪的軟件革新的浪潮中只能作壁上觀了。