這一章介紹如何用WebSocket API來控制協議和創建應用,運用http://websocket.org 提供的現有WebSocket服務器,我們可以收發消息、創建一些簡單的WebSocket應用。一步一步的學習使用WebSocket API,最后我們會討論瀏覽器的支持度和連通性。這一章的重點是WebSocket 協議在Web客戶端的應用,在稍后的章節會介紹WebSocket協議以及其使用環境。
綜述:
入門:
// Create new WebSocket connection var ws = new WebSocket("ws://www.websocket.org"); //測試了下鏈接不上。
// Connecting to the server with one protocol called myProtocol var ws = new WebSocket("ws://echo.websocket.org", "myProtocol"); //myProtocol 是假設的一個定義好的且符合標准的協議。
你可以傳遞一個協議的數組。
var echoSocket = new WebSocket("ws://echo.websocket.org", ["com.kaazing.echo","example.imaginary.protocol"]) //服務端會選擇其中一個使用 echoSocket.onopen = function(e) { // Check the protocol chosen by the server console.log(echoSocket.protocol); }
輸出:com.kaazing.echo

WebSocket事件:
open:
// Event handler for the WebSocket connection opening ws.onopen = function(e) { console.log("Connection open..."); };
open事件觸發的時候,意味着協議握手結束,WebSocket已經准備好收發數據。如果你的應用收到open事件,就可以確定服務端已經處理了建立連接的請求,且同意和你的應用通信。
Message:
// 接受文本消息的事件處理實例: ws.onmessage = function(e) { if(typeof e.data === "string"){ console.log("String message received", e, e.data); } else { console.log("Other message received", e, e.data); } };
除了文本消息,WebSocket消息機制還能處理二進制數據,有Blob和ArrayBuffer兩種類型,在讀取到數據之前需要決定好數據的類型。
// 設置二進制數據類型為blob(默認類型) ws.binaryType = "blob"; // Event handler for receiving Blob messages ws.onmessage = function(e) { if(e.data instanceof Blob){ console.log("Blob message received", e.data); var blob = new Blob(e.data); } };
//ArrayBuffer ws.binaryType = "arraybuffer"; ws.onmessage = function(e) { if(e.data instanceof ArrayBuffer){ console.log("ArrayBuffer Message Received", + e.data); // e.data即ArrayBuffer類型 var a = new Uint8Array(e.data); } };
Error
//異常處理 ws.onerror = function(e) { console.log("WebSocket Error: " , e); //Custom function for handling errors handleErrors(e); };
Close
當然你可以調用close方法斷開與服務端的鏈接來觸發onclose事件,
ws.onclose = function(e) { console.log("Connection closed", e); };
連接失敗和成功的關閉握手都會觸發關閉事件,WebSocket的對象的readyState屬性就代表連接的狀態(2代表正在關閉,3代表已經關閉)。關閉事件有三個屬性可以用來做異常處理和重獲: wasClean,code和reason。wasClean是一個bool值,代表連接是否干凈的關閉。 如果是響應服務端的close事件,這個值為true,如果是別的原因,比如因為是底層TCP連接關閉,wasClean為false。code和reason代表關閉連接時服務端發送的狀態,這兩個屬性和給入close方法的code和reason參數是對應的,稍后會描述細節。
WebSocket 方法:
WebSocket 對象有兩個方法:send()和close()
send():
一旦在服務端和客戶端建立了全雙工的雙向連接,可以使用send方法去發送消息,
//發送一個文本消息 ws.send("Hello WebSocket!");
當連接是open的時候send()方法傳送數據,當連接關閉或獲取不到的時候回拋出異常。一個通常的錯誤是人們喜歡在連接open之前發送消息。如下所示:
// 這將不會工作 var ws = new WebSocket("ws://echo.websocket.org") ws.send("Initial data");
正確的姿勢如下,應該等待open事件觸發后再發送消息。
var ws = new WebSocket("ws://echo.websocket.org") ws.onopen = function(e) { ws.send("Initial data"); }
如果想通過響應別的事件去發送消息,可以檢查readyState屬性的值為open的時候來實現。
function myEventHandler(data) { if (ws.readyState === WebSocket.OPEN) { //open的時候即可發送 ws.send(data); } else { // Do something else in this case. //Possibly ignore the data or enqueue it. } }
發送二進制數據:
// Send a Blob var blob = new Blob("blob contents"); ws.send(blob); // Send an ArrayBuffer var a = new Uint8Array([8,6,7,5,3,0,9]); ws.send(a.buffer);
Blob對象和JavaScript File API一起使用的時候相當有用,可以發送或接受文件,大部分的多媒體文件,圖像,視頻和音頻文件。這一章末尾會結合File API提供讀取文件內容來發送WebSocket消息的實例代碼。
close()
使用close方法來關閉連接,如果連接以及關閉,這方法將什么也不做。調用close方法只后,將不能發送數據。
ws.close();
close方法可以傳入兩個可選的參數,code(numerical)和reason(string),以告訴服務端為什么終止連接。第三章講到關閉握手的時候再詳細討論這兩個參數。
// 成功結束會話 ws.close(1000, "Closing normally"); //1000是狀態碼,代表正常結束。
WebSocket 屬性
WebSocket對象有三個屬性,readyState,bufferedAmount和Protocol。
readyState:
WebSocket對象通過只讀屬性readyState來傳達連接狀態,它會更加連接狀態自動改變。下表展示了readyState屬性的四個不同的值。
屬性
|
值
|
狀態
|
WebSocket.CONNECTING
|
0 |
連接正在進行,但還沒有建立
|
WebSocket.OPEN
|
1
|
連接已經建立,可以發送消息。 |
WebSocket.CLOSING
|
2
|
連接正在進行關閉握手 |
WebSocket.CLOSED
|
3
|
連接已經關閉或不能打開 |
了解當前連接的狀態有助於我們調試。
bufferedAmount:
// 10k var THRESHOLD = 10240; //建立連接 var ws = new WebSocket("ws://echo.websocket.org"); // Listen for the opening event ws.onopen = function () { setInterval( function() { //緩存未滿的時候發送 if (ws.bufferedAmount < THRESHOLD) { ws.send(getApplicationState()); } }, 1000); }; //使用bufferedAmount屬性發送數據可以避免網絡飽和。
protocol:
在構造函數中,protocol參數讓服務端知道客戶端使用的WebSocket協議。而WebSocket對象的這個屬性就是指的最終服務端確定下來的協議名稱,當服務端沒有選擇客戶端提供的協議或者在連接握手結束之前,這個屬性都是空的。
完整實例
<h2>Websocket Echo Client</h2> <div id="output"></div>
// 初始化連接和事件 function setup() { output = document.getElementById("output"); ws = new WebSocket("ws://echo.websocket.org/echo"); // 監聽open ws.onopen = function (e) { log("Connected"); sendMessage("Hello WebSocket!"); } // 監聽close ws.onclose = function (e) { log("Disconnected: " + e.reason); } //監聽errors ws.onerror = function (e) { log("Error "); } // 監聽 messages ws.onmessage = function (e) { log("Message received: " + e.data); //收到消息后關閉 ws.close(); } } // 發送消息 function sendMessage(msg) { ws.send(msg); log("Message sent"); } // logging function log(s) { var p = document.createElement("p"); p.style.wordWrap = "break-word"; p.textContent = s; output.appendChild(p); // Also log information on the javascript console console.log(s); } // Start setup();
判斷瀏覽器是否支持:
if (window.WebSocket){ console.log("This browser supports WebSocket!"); } else { console.log("This browser does not support WebSocket."); }