WebSocket系列之二進位制資料設計與傳輸

黃Java發表於2018-03-31

概述

通過前三篇部落格,我們能夠了解在通過WebSocket傳送資料之前,我們需要傳遞的資料是如何變成ArrayBuffer二進位制資料的;在我們收到二進位制資料之後,我們又如何將其變成了JavaScript中的常見資料型別。 本文作為WebSocket系列的第四篇內容,將會用一個簡單的IM聊天應用把整個WebSocket傳輸二進位制資料型別的內容連線起來,讓使用者對整個WebSocket傳輸二進位制資料的方法有個瞭解。 本文的主要內容如下:

  • 如何設計一個二進位制協議
  • WebSocket如何傳送二進位制資料
  • WebSocket如何處理接收的二進位制資料

之前的部落格我們介紹過了WebSocket基礎知識,數字型別和字串型別與二進位制資料間的轉換,如果沒有相關的基礎,建議先依次閱讀以下文章:

如何設計一個二進位制協議

什麼是協議

協議,網路協議的簡稱,網路協議是通訊計算機雙方必須共同遵從的一組約定。如怎麼樣建立連線、怎麼樣互相識別等。只有遵守這個約定,計算機之間才能相互通訊交流。它的三要素是:語法、語義、時序。

通過百度百科中的介紹,我們對協議的概念有了一個基礎的瞭解。通俗來說,協議就是通訊雙方約定好的一套規則。

為什麼要設計協議

沒有規矩不成方圓。通訊雙方只有通過協議,才能夠識別對方傳送的資料內容。

我們應該如何設計這套協議

首先,協議的設計應該能夠區分不同的各個資料包;其次,它還需要具備一定的相容性。 根據上述兩點要求,我們設計了一套簡單的IM聊天協議,支援文字、圖片、檔案三種訊息。這套協議是按照最簡單的思路來設計的,因此也只是給大家一個參考的觀點,在真正的線上使用場景中,協議會比本文中的複雜和更加有層次。具體格式如下:

{
    "id": "short", // 訊息型別,1是文字協議格式;2是圖片協議格式;3是檔案協議格式
    "sender": "long", // 傳送使用者唯一id
    "reciever": "long", // 接受使用者唯一id
    "data": "string" // 訊息內容,如果是文字協議則為文字內容;如果是圖片協議則為圖片地址;如果是檔案協議則為檔案地址
}
複製程式碼

這套協議如何使用

傳送訊息

從協議格式可知,將上述資料按照上述固定順序放入ArrayBuffer中,即可得到一個有特定含義的二進位制資料。例如:

{
    "id": 1,
    "sender": "123",
    "reciever": "456",
    "data": "Hellow World"
}
複製程式碼

當我們需要傳送此訊息時,只需要:

  1. 在前2個Byte放入id
  2. 接下來8個Byte中放入sender
  3. 再接下來8個Byte放入reciever
  4. 最後緊接著放入一個string型別(以WebSocket系列之字串如何與二進位制資料進行轉換部落格中的格式為例,先將字串長度構造成一個int型別,放在前4個Byte中,接下來將string型別編碼後放入)。 此資料就完全按照協議構造完成了。我們只需將次協議通過WebSocket傳送即可。具體方法將會在後面章節中說明。

接收訊息

從協議格式可知,當我們收到一條訊息時,只需要按照協議規範來進行反向解析即可。例如:

{
    "id": 1,
    "sender": "123",
    "reciever": "456",
    "data": "Hellow World"
}
複製程式碼

如果傳送端傳送的資料仍然為此訊息,我們的解析順序為:

  1. 先根據前2個Byte讀取一個Short型別的id數值。
  2. 將接下來的8個Byte讀取為Long型別的sender欄位。
  3. 再接下來的8個Byte讀取為Long型別的reciever欄位。
  4. 接下來讀取一個string型別(以傳送訊息這一節的資料為例,先讀取4個Byte長度的int型別字串長度,然後再根據長度讀取字串即可)。

擴充套件此協議

當此協議欄位無法滿足並且已經線上上使用時,我們應該如何擴充套件呢? 根據我們的寫入和讀取步驟,我們可以知道:**每次我們讀取的二進位制資料可以認為是一個格式固定的資料(string型別在構造時會有長度資訊,因此認為也是長度相對固定),所以我們在讀取二進位制資料時讀取的長度也是固定的。**因此,我們在擴充套件時只需要往協議後面增加欄位即可。

  • 擴充套件前的應用仍然會讀取之前已經確定的資料協議,只需要保證內容不變,那麼功能也不會變。
  • 擴充套件後的應用能夠解析擴充套件後的協議,因此得到更多的資料,從而可以實現更多的功能。

WebSocket如何傳送二進位制資料

通過如何設計一個二進位制協議一章,我們知道了如何定義WebSocket傳輸的二進位制資料格式。下面,我們來看下如何在WebSocket中傳送二進位制資料:

let arrayBuffer = getArrayBufferMessagesFromUser(); // 獲取使用者需要傳送的訊息資料,為一個ArrayBuffer物件
let webSocket = getWebSocket(); // 獲取已經連線成功的WebSocket例項

websocket.binaryType = 'arraybuffer'; // 指定WebSocket接受ArrayBuffer例項作為引數

webSocket.send(arrayBuffer);
複製程式碼

通過上面的示例我們可以知道,WebSocket在傳送string型別的資料或者ArrayBuffer型別的資料時,使用的API介面都是send方法,我們只需要在WebSocket初始化後指定傳輸型別binaryType即可。

WebSocket如何處理接收的二進位制資料

通過WebSocket如何傳送二進位制資料一章,我們知道了如何傳送二進位制資料。接下來,讓我們開看下如何處理WebSocket接收到的二進位制資料:

let webSocket = getWebSocket(); // 獲取已經連線成功的WebSocket例項

websocket.binaryType = 'arraybuffer'; // 指定WebSocket接受ArrayBuffer例項作為引數

webSocket.addEventListener('message', (message) => {
    let arrayBuffer = message.data; // 獲取使用者接收到的訊息資料,為一個ArrayBuffer物件
    let data = parseMessage(arrayBuffer); // 解析二進位制資料
});
複製程式碼

通過上面的示例我們可以知道,當我們在建立連線時指定了傳輸型別binaryType為ArrayBuffer之後,我們通過WebSocket收到的資料也是一個ArrayBuffer例項。我們只需要根據第一章講解的方式進行解析即可。

總結

本文作為WebSocket系列的第四篇,通過一個IM聊天應用的示例將前三篇部落格分享的內容串聯起來,給讀者完整介紹了在WebSocket中使用二進位制資料進行傳輸的方法以及相關的資料型別轉換。 通過前面4篇部落格的內容,讀者可以根據自己的需求快速的構造和封裝WebSocket進行二進位制資料傳輸,基本能夠串聯整個應用流程。 WebSocket系列下一篇文章將會介紹線上上環境中,如何保證WebSocket的連線,以及線上可能遇到的問題。通過應對WebSocket可能出現的問題,我們能夠讓整個長連線更加健壯。

相關文章