JavaScript進行WebSocket位元組流通訊樣本

來源:互聯網
上載者:User

標籤:響應   拼接   檢測   connect   數值   div   eth   int   串連   

websocket進行通訊時,可以選擇採用字串或者位元組流的傳輸模式。但在發送與接收時,需要考慮資料的分包,即分成一個個請求與響應訊息。無論是採用哪種傳輸模式,都不免要遇到這個問題。

採用字串傳輸時,接收端可以將每次接收到的字串拼接到一起,再檢測是否出現了某一特定子串,比如連續兩個換行,即可將一個長的字串分隔成一個個的請求或響應訊息。這種處理方式比較簡單且有效。但這裡,介紹另一種模式,即傳輸位元組流。

首先考慮下分包的問題,一般分為訊息頭與訊息體。出於簡單目的,訊息頭裡只存放一個訊息體的長度,訊息體為位元組數組。

確定了資料包格式接下來可以寫實現代碼了,首先是串連:

var socket;var uri = "ws://" + window.location.host + "/push";  // 樣本地址function Connect(uri) {    socket = new WebSocket(uri);    socket.binaryType = "arraybuffer";    socket.onopen = function (e) {        console.log("已串連至伺服器");    };    socket.onclose = function (e) {        console.log("連結已關閉");    };    socket.onmessage = function (e) {        doReceive(e.data);    };    socket.onerror = function (e) {        console.log("出現錯誤");    };}

這裡將socket變數定義為公用的,因為後續的發送方法會用到這個變數。預設JavaScript裡的WebSocket傳輸是採用字串模式的,採用UTF-8編碼,通過將binaryType屬性設定為arraybuffer來使用位元組流傳輸。

當發生onmessage事件時代表接收到資料,儲存在參數e.data裡。每一次接收都可能接收到一個完整的訊息或部分訊息,我們通過一個doReceive方法來進行訊息資料包的拆分。代碼如下:

var receive = [];var length = 0;function doReceive(buffer) {    receive = receive.concat(Array.from(new Uint8Array(buffer)));    if (receive.length < 4) {        return;    }    length = new DataView(new Uint8Array(receive).buffer).getUint32(0);    if (receive.length < length + 4) {        return;    }    var bytes = receive.slice(4, length + 4);    doSomething(bytes);    receive = receive.slice(length + 4);};

其中receive作為接收緩衝區,每次接收到資料時先將其存到該緩衝區裡。之後檢查其長度是否大於等於4位元組,即上文定義的訊息頭長度。若滿足條件,則將其作為Uint32值讀取,代表訊息體長度。之後檢查緩衝區是否大於訊息頭加訊息體長度,若滿足則讀取訊息體,之後得到的bytes位元組數組即為完整的訊息體。最後,用剩餘位元組重設緩衝區以備下一次讀取。

其中buffer參數為ArrayBuffer類型,其代表原始的位元組數組,本身是無意義的。JavaScript通過一個個視圖來解釋這些位元組。Uint8Array即是其中一種視圖,它將ArrayBuffer中的位元組作為8位不帶正負號的整數來對待,正好一位元組對應一個uint8整數。類似的還有Uint16Array,它將ArrayBuffer中的位元組作為16位不帶正負號的整數來對待,則每兩位對應一個uint16整數。

而DataView是JavaScript API提供的一種視圖,他將ArrayBuffer中的資料作為網路流對待,它採用大端編碼,可以用它來讀取或寫入資料。這裡我們用它讀取了一個Uint32的值。

接下來是發送方法,代碼如下:

function doSend(bytes) {    var buffer = new ArrayBuffer(bytes.length + 4);    var view = new DataView(buffer);    view.setUint32(0, bytes.length);    for (var i = 0; i < bytes.length; i++) {        view.setUint8(i + 4, bytes[i]);    }    socket.send(view);};

其中參數bytes是已經編碼過的位元組數組,這裡通過DataView視圖將其儲存到ArrayBuffer對象裡,以備發送。按照上文約定,需先設定Uint32型的訊息體長度,再設定訊息體。

最後,本文按約定的訊息格式來進行請求與響應訊息的傳輸,訊息體為不定長度的位元組序列。其本身是無意義的。我們可以通過API提供的Uint16Array、Uint32Array等視圖將其作為整數值序列,也可以自我實現其內容的解釋方式。

比如參考這裡將其作為採用UTF-8編碼的字串。之後可再將字串列印或還原序列化為JSON對象等。

JavaScript進行WebSocket位元組流通訊樣本

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.