WebSockets 簡介:將套接字引入網絡

問題:低延遲的客戶端-服務器和服務器-客戶端連接

一直以來,網絡在很大程度上都是圍繞着所謂 HTTP 的請求/響應模式而構建的。客戶端加載一個網頁,然後直到用戶點擊下一頁之前,什麼都不會發生。在 2005 年左右,AJAX 開始讓網絡變得更加動態了。但所有 HTTP 通信仍然是由客戶端控制的,這就需要用戶互動或定期輪詢,以便從服務器加載新數據。

長期以來存在着各種技術,可讓服務器得知有新數據可用時,立即將數據發送到客戶端。這些技術名目繁多,例如“推送”或 Comet。最普遍的一種***手段是對服務器發起的鏈接創建假象,這稱爲長輪詢。利用長輪詢,客戶端可打開指向服務器的 HTTP 連接,而服務器會一直保持連接打開,直到發送響應。服務器只要實際擁有新數據,就會發送響應(其他技術包括 FlashXHR multipart 請求和所謂的htmlfiles)。長輪詢和其他技術非常好用,您在 Gmail 聊天等應用中經常使用它們。

但是,這些解決方案都存在一個共同的問題:它們帶有 HTTP 的開銷,導致它們不適用於低延遲應用。可以想象一下瀏覽器中的多人第一人稱射擊遊戲,或者其他任何帶有即時要素的在線遊戲。

WebSocket 簡介:將套接字引入網絡

WebSocket 規範定義了一種 API,可在網絡瀏覽器和服務器之間建立“套接字”連接。簡單地說:客戶端和服務器之間存在持久的連接,而且雙方都可以隨時開始發送數據。

使用入門

只需調用 WebSocket 構造函數即可打開 WebSocket 連接:

var connection =newWebSocket('ws://html5rocks.websocket.org/echo',['soap','xmpp']);

請注意 ws:。這是 WebSocket 連接的新網址架構。對於安全 WebSocket 連接還有wss:,就像 https: 用於安全 HTTP 連接一樣。

立即向連接附加一些事件處理程序可讓您知道連接打開、收到傳入訊息或出現錯誤的時間。

第二個參數可接受可選子協議,它既可以是字符串,也可以是字符串數組。每個字符串都應代表一個子協議名稱,而服務器只能接受數組中通過的一個子協議。訪問 WebSocket 對象的 protocol 屬性可確定接受的子協議。

子協議名稱必須是 IANA 註冊表中的某個註冊子協議名稱。截止 2012 年 2 月,只有一個註冊子協議名稱 (soap)。

// When the connection is open, send some data to the server
connection.onopen = function () {
  connection.send('Ping'); // Send the message 'Ping' to the server
};
// Log errors
connection.onerror = function (error) {
  console.log('WebSocket Error ' + error);
};
// Log messages from the server
connection.onmessage = function (e) {
  console.log('Server: ' + e.data);
};

與服務器通信

與服務器建立連接後(啓動 open 事件時),我們可以開始對連接對象使用send('your message') 方法,向服務器發送數據。該方法以前只支持字符串,但根據最新的規範,現在也可以發送二進制訊息了。要發送二進制數據,您可以使用BlobArrayBuffer 對象。

// Sending String
connection.send('your message');
// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
  binary[i] = img.data[i];
}
connection.send(binary.buffer);
// Sending file as Blob
var file = document.querySelector('input[type="file"]').files[0];
connection.send(file);

同樣,服務器也可能隨時向我們發送訊息。只要發生這種情況,就會啓動onmessage 回調。該回調接收的是事件對象,而實際的訊息可通過 data 屬性進行訪問。

在最新規範中,WebSocket 也可以接收二進制訊息。接收的二進制幀可以是 BlobArrayBuffer 格式。要指定收到的二進制數據的格式,可將 WebSocket 對象的 binaryType 屬性設爲“blob”或“arraybuffer”。默認格式爲“blob”(您不必在發送時校正 binaryType 參數)。

// Setting binaryType to accept received binary as either 'blob' or 'arraybuffer'
connection.binaryType = 'arraybuffer';
connection.onmessage = function(e) {
  console.log(e.data.byteLength); // ArrayBuffer object if binary
};

WebSocket 的另一個新增功能是擴展。利用擴展,可以發送壓縮幀、多路複用幀等。您可以檢查 open 事件後的 WebSocket 對象的 extensions 屬性,查找服務器所接受的擴展。截止 2012 年 2 月,還沒有官方發佈的擴展規範。

// Determining accepted extensions
console.log(connection.extensions);

跨源通信

作爲現代協議,跨源通信已內置在 WebSocket 中。雖然您仍然應該確保只與自己信任的客戶端和服務器通信,但 WebSocket 可實現任何域上多方之間的通信。服務器將決定是向所有客戶端,還是隻向駐留在一組指定域上的客戶端提供服務。


代理服務器

每一種新技術在出現時,都會伴隨着一系列問題。WebSocket 也不例外,它與大多數公司網絡中用於調解 HTTP 連接的代理服務器不兼容。WebSocket 協議使用 HTTP 升級系統(通常用於 HTTP/SSL)將 HTTP 連接“升級”爲 WebSocket 連接。某些代理服務器不支持這種升級,並會斷開連接。因此,即使指定的客戶端使用了 WebSocket 協議,可能也無法建立連接。這就使得下一部分的內容更加重要了。

立即使用 WebSocket

WebSocket 仍是一項新興技術,並未在所有瀏覽器中全面實施。而在無法使用 WebSocket 的情況下,只要通過一些使用了上述某個回調的庫,就可以立即使用 WebSocket 了。在這一方面使用非常普遍的庫是 socket.io,其中自帶了協議的客戶端和服務器實施,幷包含回調(截止 2012 年 2 月,socket.io 還不支持二進制訊息傳輸)。還有一些商業解決方案,例如 PusherApp,通過提供向客戶端發送 WebSocket 訊息的 HTTP API,可輕鬆地集成到任何網絡環境中。由於額外的 HTTP 請求,這些解決方案與純 WebSocket 相比總是會有額外的開銷。

服務器端

使用 WebSocket 爲服務器端應用帶來了全新的用法。雖然 LAMP 等傳統服務器堆棧是圍繞 HTTP 請求/響應循環而設計的,但是通常無法很好地處理大量打開的 WebSocket 連接。要同時維持大量連接處於打開狀態,就需要能以低性能開銷接收高併發數據的架構。此類架構通常是圍繞線程或所謂的非阻塞 IO 而設計的。

服務器端實施

協議版本

現在,WebSocket 的單線協議(客戶端與服務器之間的握手和數據傳輸)是RFC6455。最新版的 Chrome 瀏覽器和 Android 版 Chrome 瀏覽器與 RFC6455 完全兼容(包括二進制訊息傳輸)。另外,Firefox 11 和 Internet Explorer 10 也會實現兼容。您仍可以使用舊版協議,但由於它們已知存在漏洞,我們不建議使用。如果您有舊版 WebSocket 協議的服務器實施,我們建議您將其更新到最新版本。


用例

如果您需要在客戶端與服務器之間建立極低延遲、近乎即時的連接,則可使用 WebSocket。請記住,這可能需要您重新考慮構建服務器端應用的方式,將新的關注點放在事件隊列等技術上。以下是一些用例:

  • 多人在線遊戲

  • 聊天應用

  • 體育賽況直播

  • 即時更新社交信息流

演示

參考


以上內容來自:http://www.html5rocks.com/zh/tutorials/websockets/basics/#toc-usecases

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章