這篇算是延續之前的《HTML5 WebSocket Client》和《C++ WebSocket 函式庫:WebSocket++》這兩篇文章,來整理一下,除了傳遞文字資料外,要怎麼透過 WebSocket 來傳遞 Binary 資料。而 client 端基本上還是一般的 JavaScript、Server 端也就還是 WebSocket++ 了~
基本上,WebSocket 在 JavaScript 這端,除了純文字(DOMString),在二進位資料的方面,還支援 Blob 和 ArrayBuffer 兩種類型的資料。Blob 基本上是一種沒有特定原生 JavaSctipt 型別的 RAW Data,裡面可以塞各式各樣的東西(參考);而 ArrayBuffer 則是固定寬度的陣列資料,不過由於本身沒有記錄內容的型別,所以必須透過 ArrayBufferView 的物件、來指定內容的型別做存取(參考)。
而 Heresy 這邊,基本上就是使用 ArrayBuffer 來做資料的傳遞 C++ 裡面的陣列。
JavaScript Client
基本上,要在 JavaScript 裡面接收 WebSocket 傳來的 ArrayBuffer 資料,在程式架構上,並不需要做太大的修改;要注意的是,由於 WebSocket 支援的 Binary 資料形式有 Blob 和 ArrayBuffer 兩種,所以必須要手動指定要用哪種類型的資料。
而指定的方法,基本上就是在建立出 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++ 是要使二進位的資料,所以指定 opcode 是 BINARY。
而如果要傳遞其他型別的陣列,也只要用同樣的方法,就可以了~
這篇先到這裡,接下來應該是準備來研究怎麼透過 WebSocket 來傳影像了。
請問,用winsocket++傳送影像, 需要將資料分成多筆資料嗎?每筆資料的大小有限制?或者最佳的大小是多少 ?
讚讚
個人之前在用的時候都沒有特別去切割資料。
讚讚
您好,請問透過websocket++ sercer 上,用on_message確認client的所取狀態,並在on_message裡,用迴圈每讀取video的一張frame便傳送一個 data array 給 client一次,可是最後再client(js)上卻發生等待server接收完整個oni的影像才開始顯示,請問有其他方式去傳送影像讓client端可以收到一張便顯示一張?謝謝。
讚讚
這和 WebSocket++ 基本上沒關係,而是看你自己的程式怎麼寫的…
讚讚
[…] Heresy 這邊,基本上就是透過 WebSocket 的 ArrayBuffer(參考),來把 JPEG 檔的資料(Heresy […]
讚讚
[…] 透過 WebSocket 傳送 Binary 資料:ArrayBuffer […]
讚讚
[…] Heresy 這邊,基本上就是透過 WebSocket 的 ArrayBuffer(參考),來把 JPEG 檔的資料(Heresy […]
讚讚
[…] WebSocket 傳送 Binary 資料:ArrayBuffer》作一些補充。 在《透過 WebSocket 傳送 Binary 資料:ArrayBuffer》一文中,Heresy 主要是在針對由 WebSocket++ 的 C++ Server,傳遞 binary […]
讚讚