這兩年中,HTML5發展的如火如荼,再不學習一下,覺得自己都落後了。說到HTML5,最讓我驚心動魄的特性我覺得就是全新的WebSocket通信協議了。有"Web通信TCP"之稱的 WebSocket的出現使得瀏覽器提供對 Socket 的支持成爲可能,從而在瀏覽器和服務器之間提供了一個基於TCP連接的雙向通道。Web開發人員可以非常方便地使用WebSocket構建實時web應用。
Web的交互過程
這種機制對於信息變化不是特別頻繁的應用尚能相安無事,但是對於那些實時要求比較高的應用來說(比如說在線遊戲),當客戶端瀏覽器準備呈現獲取到的信息的時候,這些信息在服務器端可能已經過時了,所以保持客戶端和服務器端的信息同步是實時 Web 應用的關鍵要素。在WebSocket規範出來之前,開發人員想實現這種應用,不得不採用一些折衷的方案,其中最常用的就是輪詢 (Polling) 和 Comet(輪詢的改進版本,又可細分爲長輪詢機制與流技術) 技術。這幾種方案,基本都是在用 Ajax 方式來模擬實時的效果,服務器與客戶端編程都比較複雜,而且效率不高。
HTML5 WebSocket設計出來的目的就是要取代輪詢和Comet技術,使客戶端瀏覽器具備像C/S架構下桌面系統的實時通訊能力。 瀏覽器向服務器發出建立WebSocket連接的請求,連接建立以後,客戶端和服務器端就可以通過TCP連接直接交換數據。因爲WebSocket連接本質上就是一個TCP連接,所以在數據傳輸的穩定性和數據傳輸量的大小方面,和輪詢以及Comet技術比較,具有很大的性能優勢。這種統計數據在網上很多,這裏我選了一幅圖,只能說我看到對比數據時,當場震驚了。
WebSocket協議
WebSocket協議本質上是一個基於TCP的協議。爲了建立一個WebSocket連接,客戶端瀏覽器首先要向服務器發起一個HTTP請求,這個請求和通常的HTTP請求不同,包含了一些附加頭信息,其中附加頭信息”Upgrade: WebSocket”表明這是一個申請協議升級的 HTTP 請求(詳細的WebSocket消息的內容這裏就不詳細說了,基本和HTTP的差不多,而且都是由WebSocket對象自動發送和接收的,對用戶透明),服務器端解析這些附加的頭信息然後產生應答信息返回給客戶端,客戶端和服務器端的 WebSocket 連接就建立起來了,雙方就可以通過這個連接通道自由的傳遞信息,並且這個連接會持續存在直到客戶端或者服務器端的某一方主動的關閉連接。
WebSocket API最偉大之處在於服務器和客戶端可以在給定的時間範圍內的任意時刻,相互推送信息。WebSocket並不限於以Ajax(或XmlHttpRequest)方式通信,因爲Ajax技術需要客戶端發起請求,而WebSocket服務器和客戶端可以彼此相互推送信息;XmlHttpRequest通信受到域的限制,而WebSocket允許跨域通信。
需要注意的問題是,除了安全和性能以外,服務端只管往socket裏面寫數據就可以了,WebSocket的通信數據全部是以”\x00″開頭以”\xFF”結尾的,無論是服務端發出的數據還是客戶端發送的數據都遵從這個格式,唯一不同的是客戶端的WebSocket對象能夠自動將頭尾去除,獲得主體數據,這就省卻了在客戶端處理原始數據的必要,而且WebSocket通信的消息總是UTF-8格式的。
WebSocket 服務端編程模型
- Kaazing WebSocket Gateway: 一個 Java 實現的WebSocket Server
- mod_pywebsocket: 一個 Python 實現的WebSocket Server
- Netty:一個 Java 實現的網絡框架其中包括了對WebSocket的支持
- node.js:一個 Server 端的 JavaScript 框架提供了對WebSocket的支持
- ...
如果以上的 WebSocket 服務端實現不能滿足當前的業務需求的話,開發人員完全可以根據 WebSocket 規範自己實現一個服務器。也正是由於有JavaScript的版本,才使得JavaScript脫離了瀏覽器的限制,走向服務器端,從而再次進入人們的視線中。
服務端的編程一般是要處理以下任務:
- 運行HTTP服務器;
- 對於不同的請求,根據請求的URL,服務器給予不同的響應,也就是路由程序,用於把請求對應到請求處理程序;
- 當請求被服務器接收並通過路由傳遞之後,需要可以對其進行處理,因此我們需要最終的請求處理程序 。
最簡單的服務端程序就是啓動HTTP服務器,如下所示:
http.createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}).listen(8888);
啓動服務器以後,在瀏覽器中輸入://localhost:8888就可以顯示"Hello World"了。
WebSocket客戶端編程模型
WebSocket編程實際上就連接服務器並處理各種事件,下面是JavaScript的接口:
interface WebSocket {
readonly attribute DOMString URL;
// ready state
const unsigned short CONNECTING = 0;
const unsigned short OPEN = 1;
const unsigned short CLOSED = 2;
readonly attribute unsigned short readyState;
readonly attribute unsigned long bufferedAmount;
//networking
attribute Function onopen;
attribute Function onmessage;
attribute Function onclose;
boolean send(in DOMString data);
void close();
};
WebSocket implements EventTarget;
其中URL屬性代表WebSocket服務器的網絡地址,協議通常是"ws"(也可以是"wss"), send 方法就是發送數據到服務器端,close 方法就是關閉連接。除了這些方法,還有一些很重要的事件:onopen,onmessage,onerror 以及 onclose。
下面就是一個典型的客戶端編程模型,至於網站提供的功能,那就是JavaScript與html5的事了。
var websocket = new WebSocket(wsServer);
websocket.onopen = function (evt) { onOpen(evt) };
websocket.onclose = function (evt) { onClose(evt) };
websocket.onmessage = function (evt) { onMessage(evt) };
websocket.onerror = function (evt) { onError(evt) };
function onOpen(evt) {
console.log("Connected to WebSocket server.");
}
function onClose(evt) {
console.log("Disconnected");
}
function onMessage(evt) {
console.log('Retrieved data from server: ' + evt.data);
}
function onError(evt) {
console.log('Error occured: ' + evt.data);
}
WebSocket 的風險
目前對HTML5支持的比較好的主流的瀏覽器如下:Firefox 4、Chrome 4、Opera 10.70以及Safari 5。推薦還是安裝Chrome瀏覽器,速度快,調試工具好。