HTML5 WebSocket Client


最近因為有需要開發互動式網頁,而且又需要頻繁地和 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

整個程式執行的流程,大致如下:

  1. 首先,當建立了一個 WebSocket 連線後,接下來通常都會是因為能正確地連線,所以會出發到 onopen 的事件,所以會去執行 onOpen() 這個函式;而這個函式所做的事,就是先輸出一個「CONNECTED」的字串,然後再呼叫 doSend() 這個函式,送出「WebSocket rocks」這個字串。

    而實際上,要透過 WebSocket 來送出訊息,也相當簡單,只要呼叫 WebSocket 物件(websocket)的 send() 這個函式就可以了~

  2. 接下來,Server 端的部分,應該是設計成在收到 client 端送來的訊息後,就原封不動地,把訊息再送回給 client 端,所以接下來,這個網頁就會因為收到 Server 端送來的訊息,而觸發到 onmessage 的事件,進而呼叫 onMessage() 這個函式。

    而在這個範例程式裡,在收到 Server 端送來的訊息(evt)後,就會把他的資料(evt.data)作輸出(上面藍色的字),並且呼叫 WebSocket 的 close() 函式,把這個連線給關閉。

  3. 而由於連線被關閉了,所以接下來則是會觸發到 onclose 的事件、進而執行 onClose() 這個函式;在這個函式裡,基本上就是很簡單地輸出「DISCONNECTED」這個字串。

所以到上面為止,就是這個範例的基本概念了~基本上,他是在連線後、傳遞、接收一個訊息後,馬上就把連線斷掉了;而如果再做修改,讓他可以持續地送訊息的話,就可以做到「echo test」這個範例網頁裡,可以持續傳遞、接收資料的功能了~而實際上,WebSocket 的 client 端程式,大概也就是以這樣的概念來寫了。

另外,onmessage 所收到的資料,實際上是一個 MessageEvent 的物件,它除了可以接收字串型別的資料外,其實也是可以接收 Blob參考)和 ArrayBuffer參考)這兩種形式的資料,所以在技術上,其實 WebSocket 是可以用來傳輸相當複雜的東西的~


參考:

對「HTML5 WebSocket Client」的想法

發表留言

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料