最近因為有需要開發互動式網頁,而且又需要頻繁地和 server 端坐溝通,所以除了 ajax 之外,也開始研究一些新的東西;而其中一個,就是可以更節省頻寬的 WebSocket、這個 HTML 5 的通訊方法了~
關於 WebSocket 的介紹,建議慶直接參考維基百科,或是 WebSocket.org 的介紹;完整的 API 則可以參考 W3C 的網頁。在 Heresy 來看,WebSocket 和傳統的 HTML 資料取得的方法相比,最大的好處,就是由於 WebSocket 是建立一個持續性的連線,不需要重複地不斷建立連線,所以可以有效地降低延遲、並且減少資料的傳輸輛。
像右圖就是 WebSocket.org 所提供的示意圖,可以看到隨著要求存取的次數的增加,傳統的「Polling」的資料存取方法所需的頻寬會上升地非常地快;相較之下,WebSocket 的頻寬則可以省非常地多。
另外,由於 WebSocket 在建立後,可以真正地由 Server 端主動送資料給 client(瀏覽器),所以也可以避免掉一來一往之間的延遲。下方就是 WebSocket.org 的示意圖:
而目前支援 WebSocket 的瀏覽器列表,可以參考:Can I Use 這個網頁或維基百科。基本上,主要的瀏覽器,只要版本夠新,都是有支援的;比較大的問題,應該會是 IE 要到 10.0 才有支援,而 Android 內建的瀏覽器則完全沒有支援。
WebSocket 的 Client 端,一般就是使用 JavaScript 來做撰寫,然後在瀏覽器內執行;他的基本使用也相當簡單,在 WebSocket.org 的網站裡,就有提供一個「Echo Test」的網頁,算是可以做最基本的說明了~他的範例程式碼如下(Heresy 自己有略做修改):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>WebSocket Test</title>
 
<script language="javascript" type="text/javascript">
var wsUri = "ws://echo.websocket.org/";
var output;
 
function init() {
output = document.getElementById("output");
testWebSocket();
}
 
function testWebSocket() {
websocket = new WebSocket(wsUri);
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) {
writeToScreen("CONNECTED");
doSend("WebSocket rocks");
}
 
function onClose(evt) {
writeToScreen("DISCONNECTED");
}
 
function onMessage(evt) {
writeToScreen('<span style="color:blue;">RESPONSE:' evt.data '</span>');
websocket.close();
}
 
function onError(evt) {
writeToScreen('<span style="color:red;">ERROR:</span>' evt.data);
}
 
function doSend(message) {
writeToScreen("SENT: " message);
websocket.send(message);
}
 
function writeToScreen(message) {
var pre = document.createElement("p");
pre.style.wordWrap = "break-word";
pre.innerHTML = message;
output.appendChild(pre);
}
 
window.addEventListener("load", init, false);
 
</script>
</head>
 
<body>
<h2>WebSocket Test</h2>
<div id="output"></div>
</body>
</html> 
首先,在這個網頁裡面,HTML 的部分相當簡單,就是一個 <H2> 的標題,和一個 id 為「output」的 <div>,用來做輸出之用。而在網頁載入完成後,他會去執行 JavaScript 的 init() 這個函式,開始進行 WebSocket 的測試。
實際上 WebSocket 測試的程式,是寫在 testWebSocket() 這個函式裡,它的使用方法相當單純,首先就是要建立一個 WebSocket 的物件,也就是:
websocket = new WebSocket(wsUri);
在這邊,傳入的字串 wsUri 的內容是「ws://echo.websocket.org/」,目的是告訴瀏覽器,這個 WebSoscket 是要連到哪裡;在這邊,就是連到 WebSocket.org 提供的測試 Server。而這個 URI 前面的「ws://」,則是代表要使用 WebSocket 這種通訊協定,如果要使用加密的連線的話,則是要改成「wss://」。
後面的網址的部分,則也可以再加上連接埠、或是其他的路徑,來當作進一步的資料;例如:「ws://localhost:12345/websocket/server.php」也是一種合法的 URI(參考)。
而之後,這個建立出來的 websocket 物件,會有四種事件,分別為:
- onopen
當連線建立時,會被觸發的事件
- onmessage
當收到 Server 端發送的訊息時,會被觸發的事件
- onclose
連線中斷時會被觸發的事件
- onerror
出現錯誤時會被觸發的事件
這邊基本上就是要針對這四種事件,來做設定,讓程式可以在事件發生時,做對應的動作。像在上面的範例程式裡,就是設定當這四種事件被觸發的時候,會去呼叫對應的函式(例如,當 onopen 的事件觸發的時候,就去呼叫 onOpen() 這個函式)。
而這個範例網頁用瀏覽器打開後,基本上應該會看到下面的結果:
WebSocket Test
CONNECTED
SENT: WebSocket rocks
RESPONSE: WebSocket rocks/message
DISCONNECTED
整個程式執行的流程,大致如下:
-
首先,當建立了一個 WebSocket 連線後,接下來通常都會是因為能正確地連線,所以會出發到 onopen 的事件,所以會去執行 onOpen() 這個函式;而這個函式所做的事,就是先輸出一個「CONNECTED」的字串,然後再呼叫 doSend() 這個函式,送出「WebSocket rocks」這個字串。
而實際上,要透過 WebSocket 來送出訊息,也相當簡單,只要呼叫 WebSocket 物件(websocket)的 send() 這個函式就可以了~ -
接下來,Server 端的部分,應該是設計成在收到 client 端送來的訊息後,就原封不動地,把訊息再送回給 client 端,所以接下來,這個網頁就會因為收到 Server 端送來的訊息,而觸發到 onmessage 的事件,進而呼叫 onMessage() 這個函式。
而在這個範例程式裡,在收到 Server 端送來的訊息(evt)後,就會把他的資料(evt.data)作輸出(上面藍色的字),並且呼叫 WebSocket 的 close() 函式,把這個連線給關閉。 -
而由於連線被關閉了,所以接下來則是會觸發到 onclose 的事件、進而執行 onClose() 這個函式;在這個函式裡,基本上就是很簡單地輸出「DISCONNECTED」這個字串。
所以到上面為止,就是這個範例的基本概念了~基本上,他是在連線後、傳遞、接收一個訊息後,馬上就把連線斷掉了;而如果再做修改,讓他可以持續地送訊息的話,就可以做到「echo test」這個範例網頁裡,可以持續傳遞、接收資料的功能了~而實際上,WebSocket 的 client 端程式,大概也就是以這樣的概念來寫了。
另外,onmessage 所收到的資料,實際上是一個 MessageEvent 的物件,它除了可以接收字串型別的資料外,其實也是可以接收 Blob(參考)和 ArrayBuffer(參考)這兩種形式的資料,所以在技術上,其實 WebSocket 是可以用來傳輸相當複雜的東西的~
參考: