WebSocket

問題:低延遲的客戶端-服務器和服務器-客戶端連接
一直以來,網(wǎng)絡在很大程度上都是圍繞著所謂 HTTP 的請求/響應模式而構建的??蛻舳思虞d一個網(wǎng)頁,然后直到用戶點擊下一頁之前,什么都不會發(fā)生。在 2005 年左右,AJAX 開始讓網(wǎng)絡變得更加動態(tài)了。但所有 HTTP 通信仍然是由客戶端控制的,這就需要用戶互動或定期輪詢,以便從服務器加載新數(shù)據(jù)。
長期以來存在著各種技術,可讓服務器得知有新數(shù)據(jù)可用時,立即將數(shù)據(jù)發(fā)送到客戶端。這些技術名目繁多,例如“推送”或 Comet。最普遍的一種黑客手段是對服務器發(fā)起的鏈接創(chuàng)建假象,這稱為長輪詢。利用長輪詢,客戶端可打開指向服務器的 HTTP 連接,而服務器會一直保持連接打開,直到發(fā)送響應。服務器只要實際擁有新數(shù)據(jù),就會發(fā)送響應(其他技術包括 Flash、XHR multipart 請求和所謂的 htmlfiles)。長輪詢和其他技術非常好用,您在 Gmail 聊天等應用中經(jīng)常使用它們。
但是,這些解決方案都存在一個共同的問題:它們帶有 HTTP 的開銷,導致它們不適用于低延遲應用。可以想象一下瀏覽器中的多人第一人稱射擊游戲,或者其他任何帶有即時要素的在線游戲。
WebSocket 簡介:將套接字引入網(wǎng)絡
WebSocket 規(guī)范定義了一種 API,可在網(wǎng)絡瀏覽器和服務器之間建立“套接字”連接。簡單地說:客戶端和服務器之間存在持久的連接,而且雙方都可以隨時開始發(fā)送數(shù)據(jù)。
使用入門
只需調(diào)用 WebSocket 構造函數(shù)即可打開 WebSocket 連接:

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

請注意 ws:
。這是 WebSocket 連接的新網(wǎng)址架構。對于安全 WebSocket 連接還有 wss:
,就像 https:
用于安全 HTTP 連接一樣。
立即向連接附加一些事件處理程序可讓您知道連接打開、收到傳入訊息或出現(xiàn)錯誤的時間。
第二個參數(shù)可接受可選子協(xié)議,它既可以是字符串,也可以是字符串數(shù)組。每個字符串都應代表一個子協(xié)議名稱,而服務器只能接受數(shù)組中通過的一個子協(xié)議。訪問 WebSocket 對象的 protocol
屬性可確定接受的子協(xié)議。
子協(xié)議名稱必須是 IANA 注冊表中的某個注冊子協(xié)議名稱。截止 2012 年 2 月,只有一個注冊子協(xié)議名稱 (soap)。

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

與服務器通信
與服務器建立連接后(啟動 open
事件時),我們可以開始對連接對象使用 send('your message')
方法,向服務器發(fā)送數(shù)據(jù)。該方法以前只支持字符串,但根據(jù)最新的規(guī)范,現(xiàn)在也可以發(fā)送二進制訊息了。要發(fā)送二進制數(shù)據(jù),您可以使用 Blob
或 ArrayBuffer
對象。

// Sending Stringconnection.send('your message');// Sending canvas ImageData as ArrayBuffervar 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 Blobvar file = document.querySelector('input[type="file"]').files[0];connection.send(file);

同樣,服務器也可能隨時向我們發(fā)送訊息。只要發(fā)生這種情況,就會啟動onmessage
回調(diào)。該回調(diào)接收的是事件對象,而實際的訊息可通過 data
屬性進行訪問。
在最新規(guī)范中,WebSocket 也可以接收二進制訊息。接收的二進制幀可以是 Blob
或 ArrayBuffer
格式。要指定收到的二進制數(shù)據(jù)的格式,可將 WebSocket 對象的 binaryType 屬性設為“blob”或“arraybuffer”。默認格式為“blob”(您不必在發(fā)送時校正 binaryType 參數(shù))。

// 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 的另一個新增功能是擴展。利用擴展,可以發(fā)送壓縮幀、多路復用幀等。您可以檢查 open 事件后的 WebSocket 對象的 extensions 屬性,查找服務器所接受的擴展。截止 2012 年 2 月,還沒有官方發(fā)布的擴展規(guī)范。

// Determining accepted extensionsconsole.log(connection.extensions);
跨源通信
作為現(xiàn)代協(xié)議,跨源通信已內(nèi)置在 WebSocket 中。雖然您仍然應該確保只與自己信任的客戶端和服務器通信,但 WebSocket 可實現(xiàn)任何域上多方之間的通信。服務器將決定是向所有客戶端,還是只向駐留在一組指定域上的客戶端提供服務。

代理服務器
每一種新技術在出現(xiàn)時,都會伴隨著一系列問題。WebSocket 也不例外,它與大多數(shù)公司網(wǎng)絡中用于調(diào)解 HTTP 連接的代理服務器不兼容。WebSocket 協(xié)議使用 HTTP 升級系統(tǒng)(通常用于 HTTP/SSL)將 HTTP 連接“升級”為 WebSocket 連接。某些代理服務器不支持這種升級,并會斷開連接。因此,即使指定的客戶端使用了 WebSocket 協(xié)議,可能也無法建立連接。這就使得下一部分的內(nèi)容更加重要了。
立即使用 WebSocket
WebSocket 仍是一項新興技術,并未在所有瀏覽器中全面實施。而在無法使用 WebSocket 的情況下,只要通過一些使用了上述某個回調(diào)的庫,就可以立即使用 WebSocket 了。在這一方面使用非常普遍的庫是 socket.io,其中自帶了協(xié)議的客戶端和服務器實施,并包含回調(diào)(截止 2012 年 2 月,socket.io 還不支持二進制訊息傳輸)。還有一些商業(yè)解決方案,例如 PusherApp,通過提供向客戶端發(fā)送 WebSocket 訊息的 HTTP API,可輕松地集成到任何網(wǎng)絡環(huán)境中。由于額外的 HTTP 請求,這些解決方案與純 WebSocket 相比總是會有額外的開銷。
服務器端
使用 WebSocket 為服務器端應用帶來了全新的用法。雖然 LAMP 等傳統(tǒng)服務器堆棧是圍繞 HTTP 請求/響應循環(huán)而設計的,但是通常無法很好地處理大量打開的 WebSocket 連接。要同時維持大量連接處于打開狀態(tài),就需要能以低性能開銷接收高并發(fā)數(shù)據(jù)的架構。此類架構通常是圍繞線程或所謂的非阻塞 IO 而設計的。
服務器端實施
Node.js
Socket.IO
WebSocket-Node
ws

Java
Jetty

Ruby
EventMachine

Python
pywebsocket
Tornado

Erlang
Shirasu

C++
libwebsockets

.NET
SuperWebSocket

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

用例
如果您需要在客戶端與服務器之間建立極低延遲、近乎即時的連接,則可使用 WebSocket。請記住,這可能需要您重新考慮構建服務器端應用的方式,將新的關注點放在事件隊列等技術上。以下是一些用例:
多人在線游戲
聊天應用
體育賽況直播
即時更新社交信息流

演示
Plink
Paint With Me
Pixelatr
Dashed
大型多人在線填字游戲
Ping 服務器(在以上示例中使用)
HTML5demos 示例

參考
WebSocket API
WebSocket 協(xié)議
WebSockets - MDN

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • WebSocket簡介 談到Web實時推送,就不得不說WebSocket。在WebSocket出現(xiàn)之前,很多網(wǎng)站為...
    吧啦啦小湯圓閱讀 8,332評論 15 75
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,658評論 19 139
  • 六月十七日晚八點,有人按響了我家的門鈴,這天江城受到某處臺風的影響,陰雨連天,夜晚的街道比平時還要陰暗許多。 “您...
    江戶川四爺閱讀 1,309評論 21 17
  • 男朋友的初戀結婚了。
    Amber琥珀色閱讀 187評論 0 0
  • 1、感恩父母給予我生命。 2、感恩祖輩將我養(yǎng)育。 3、感恩母親、祖母為家的巨大付出。 4、感恩親友們對我家的照顧。...
    朱曉軍閱讀 224評論 0 1

友情鏈接更多精彩內(nèi)容