透過 WebSocket 傳送 Binary 資料:ArrayBuffer

這篇算是延續之前的《HTML5 WebSocket Client》和《C WebSocket 函式庫:WebSocket 》這兩篇文章,來整理一下,除了傳遞文字資料外,要怎麼透過 WebSocket 來傳遞 Binary 資料。而 client 端基本上還是一般的 JavaScript、Server 端也就還是 WebSocket 了~

基本上,WebSocket 在 JavaScript 這端,除了純文字(DOMString),在二進位資料的方面,還支援 BlobArrayBuffer 兩種類型的資料。Blob 基本上是一種沒有特定原生 JavaSctipt 型別的 RAW Data,裡面可以塞各式各樣的東西(參考);而 ArrayBuffer 則是固定寬度的陣列資料,不過由於本身沒有記錄內容的型別,所以必須透過 ArrayBufferView 的物件、來指定內容的型別做存取(參考)。

而 Heresy 這邊,基本上就是使用 ArrayBuffer 來做資料的傳遞 C 裡面的陣列。


JavaScript Client

基本上,要在 JavaScript 裡面接收 WebSocket 傳來的 ArrayBuffer 資料,在程式架構上,並不需要做太大的修改;要注意的是,由於  WebSocket 支援的 Binary 資料形式有 BlobArrayBuffer 兩種,所以必須要手動指定要用哪種類型的資料。

而指定的方法,基本上就是在建立出 WebSocket 的物件後,去指定他的 binaryType 的值:

var wWebsocket = new WebSocket(sUri);
wWebsocket.binaryType = "arraybuffer";

他的值只有「arraybuffer」和「blob」兩種,在設定之後,就會以指定的形式,來處理收到的 binary 資料。

而在資料的處理方面,一樣是要在 onmessage 這個事件的 callback function 裡面做處理。基本上的概念,就是先就是要先透過 instanceof 來確認收到的資料是否為需要的型別,然後再轉換成對應的 ArrayBufferView 物件來做使用。像如果接收到的資料是 64bit 的浮點數(double),程式的寫法大致就會像下面這樣:

wWebsocket.onmessage = function (evt) {
if (evt.data instanceof ArrayBuffer)
{
var aDataArray = new Float64Array(evt.data);
for (var i = 0; i < aDataArray.length; i) {
//aDataArray[i];
}
}
};

其中,Float64Array 就是一種 ArrayBufferView 的型別;當把接收到的資料(evt.data)轉換為 Float64Array 的物件(aDataArray)後,就可以把它當作一般的陣列來做存取了~使用上算是相當地方便的。

而除了 Float64Array 這個型別外,還有其他幾種、各自對應到不同類型資料的 ArrayBufferView 型別,基本上如下表(參考):

型別
大小
對應到 C 的型別
Int8Array
1
char
Uint8Array
1
unsigned char
Int16Array
2
short
Uint16Array
2
unsigned short
Int32Array
4
int
Uint32Array
4
unsigned int
Float32Array
4
float
Float64Array
8
double

至於要轉換成哪一種型別,就是要自己和 server 端先做好溝通,搞清楚接下來要傳送的是哪一種類型的資料,才能做進一步的處理了。(這時候真的覺得 asynchronous io 很討厭…)


WebSocket Server

上面是 client 端的 JavaScript 程式,而接下來則是 WebSocket 的 Server 端程式。

基本上,WebSocket 的 endpoint 所提供的 send() 函式,本身就有提供了對應的介面,可以用來傳遞 void*、任何型別的陣列,算是相當方便的。不過由於考慮到 client 端只有提供基礎型別的 ArrayBufferView 型別來做對應,所以這邊還是建議只能來傳 C 內建的基礎型別資料的陣列就好了。

而以要傳遞一個 double 的陣列的話,大致上會是像下面這樣子:

double aData[10];
for( int i = 0; i < 10; i )
aData[i] = i;
rServer.send( hdl, aData, 10 * sizeof(double),
              websocketpp::frame::opcode::BINARY );

基本上,sned() 所需要的第一個參數,還是一樣是 connection_hdl,用來決定要傳給誰。而第二個參數,而是接受 const void*,用來接受任意型別的陣列;第三個參數,則是要告訴他這個陣列有多大,基本上就是陣列程度、乘上每一項的大小了。最後,則是要告訴 WebSocket 是要使二進位的資料,所以指定 opcodeBINARY

而如果要傳遞其他型別的陣列,也只要用同樣的方法,就可以了~


這篇先到這裡,接下來應該是準備來研究怎麼透過 WebSocket 來傳影像了。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。