WebSocket 教程

阮一峰發表於2017-05-15
WebSocket 是一種網路通訊協議,很多高階功能都需要它。

本文介紹 WebSocket 協議的使用方法。

一、為什麼需要 WebSocket?

初次接觸 WebSocket 的人,都會問同樣的問題:我們已經有了 HTTP 協議,為什麼還需要另一個協議?它能帶來什麼好處?

答案很簡單,因為 HTTP 協議有一個缺陷:通訊只能由客戶端發起。

舉例來說,我們想了解今天的天氣,只能是客戶端向伺服器發出請求,伺服器返回查詢結果。HTTP 協議做不到伺服器主動向客戶端推送資訊。

這種單向請求的特點,註定瞭如果伺服器有連續的狀態變化,客戶端要獲知就非常麻煩。我們只能使用“輪詢”:每隔一段時候,就發出一個詢問,瞭解伺服器有沒有新的資訊。最典型的場景就是聊天室。

輪詢的效率低,非常浪費資源(因為必須不停連線,或者 HTTP 連線始終開啟)。因此,工程師們一直在思考,有沒有更好的方法。WebSocket 就是這樣發明的。

二、簡介

WebSocket 協議在2008年誕生,2011年成為國際標準。所有瀏覽器都已經支援了。

它的最大特點就是,伺服器可以主動向客戶端推送資訊,客戶端也可以主動向伺服器傳送資訊,是真正的雙向平等對話,屬於伺服器推送技術的一種。

其他特點包括:

(1)建立在 TCP 協議之上,伺服器端的實現比較容易。

(2)與 HTTP 協議有著良好的相容性。預設埠也是80和443,並且握手階段採用 HTTP 協議,因此不容易遮蔽,能通過各種 HTTP 代理伺服器。

(3)資料格式比較輕量,效能開銷小,通訊高效。

(4)可以傳送文字,也可以傳送二進位制資料。

(5)沒有同源限制,客戶端可以與任意伺服器通訊。

(6)協議識別符號是ws(如果加密,則為wss),伺服器網址就是 URL。

三、客戶端的簡單示例

WebSocket 的用法相當簡單。

下面是一個網頁尾本的例子(點選這裡看執行結果),基本上一眼就能明白。

四、客戶端的 API

WebSocket 客戶端的 API 如下。

4.1 WebSocket 建構函式

WebSocket 物件作為一個建構函式,用於新建 WebSocket 例項。

執行上面語句之後,客戶端就會與伺服器進行連線。

例項物件的所有屬性和方法清單,參見這裡

4.2 webSocket.readyState

readyState屬性返回例項物件的當前狀態,共有四種。

  • CONNECTING:值為0,表示正在連線。
  • OPEN:值為1,表示連線成功,可以通訊了。
  • CLOSING:值為2,表示連線正在關閉。
  • CLOSED:值為3,表示連線已經關閉,或者開啟連線失敗。

下面是一個示例。

4.3 webSocket.onopen

例項物件的onopen屬性,用於指定連線成功後的回撥函式。

如果要指定多個回撥函式,可以使用addEventListener`方法。

4.4 webSocket.onclose

例項物件的onclose屬性,用於指定連線關閉後的回撥函式。

4.5 webSocket.onmessage

例項物件的onmessage屬性,用於指定收到伺服器資料後的回撥函式。

注意,伺服器資料可能是文字,也可能是二進位制資料(blob物件或Arraybuffer物件)。

除了動態判斷收到的資料型別,也可以使用binaryType屬性,顯式指定收到的二進位制資料型別。

4.6 webSocket.send()

例項物件的send()方法用於向伺服器傳送資料。

傳送文字的例子。

傳送 Blob 物件的例子。

傳送 ArrayBuffer 物件的例子。

4.7 webSocket.bufferedAmount

例項物件的bufferedAmount屬性,表示還有多少位元組的二進位制資料沒有傳送出去。它可以用來判斷髮送是否結束。

4.8 webSocket.onerror

例項物件的onerror屬性,用於指定報錯時的回撥函式。

五、服務端的實現

WebSocket 伺服器的實現,可以檢視維基百科的列表

常用的 Node 實現有以下三種。

具體的用法請檢視它們的文件,這裡不詳細介紹了。

六、WebSocketd

下面,我要推薦一款非常特別的 WebSocket 伺服器:Websocketd

它的最大特點,就是後臺指令碼不限語言,標準輸入(stdin)就是 WebSocket 的輸入,標準輸出(stdout)就是 WebSocket 的輸出。

舉例來說,下面是一個 Bash 指令碼counter.sh

命令列下執行這個指令碼,會輸出1、2、3,每個值之間間隔1秒。

現在,啟動websocketd,指定這個指令碼作為服務。

上面的命令會啟動一個 WebSocket 伺服器,埠是8080。每當客戶端連線這個伺服器,就會執行counter.sh指令碼,並將它的輸出推送給客戶端。

上面是客戶端的 JavaScript 程式碼,執行之後會在控制檯依次輸出1、2、3。

有了它,就可以很方便地將命令列的輸出,發給瀏覽器。

上面的命令會執行ls命令,從而將當前目錄的內容,發給瀏覽器。使用這種方式實時監控伺服器,簡直是輕而易舉(程式碼)。

更多的用法可以參考官方示例

websocketd 的實質,就是命令列的 WebSocket 代理。只要命令列可以執行的程式,都可以通過它與瀏覽器進行 WebSocket 通訊。下面是一個 Node 實現的回聲服務greeter.js

啟動這個指令碼的命令如下。

官方倉庫還有其他各種語言的例子。

七、參考連結

相關文章