websoket使用Protocol Buffers3.0傳輸


Protocol Buffers是Google推出的一個數據交換格式,相對於xml它的體積更小,更快,因為它是二進制傳輸的。3.0相對於2.0變動比較大。這些變動可以去看官方說明。

在前端使用ProtoBuf.js解析.proto文件,先需要再界面上引入protobuf.js。

定義一個.proto

syntax = "proto3";
// Token
message MyModel{
    string UserID = 1;
    string Device = 3;
}
message Message{
    string ChannelID = 1;
    bytes Content  = 4;
}

加載:

protobuf.load("Models.proto", function (err, root) {
    if (err)
        throw err;
      console.log(root);
      var MyModel = root.lookupType("MyModel");
      console.log(MyModel);
});

Root包含了我們定義的兩個模型。拿到這個模型就可以用來發送消息和解析消息了。注意到我們的上面的Message的Content是bytes類型。JavaScript本身是沒有這個類型的。

根據protobuf.js的官方說明可以通過base64編碼來實現:

function base64Encode(input) {
    var rv;
    rv = encodeURIComponent(input);
    rv = unescape(rv);
    rv = window.btoa(rv);
    return rv;
}
 var buffer1 = base64Encode("消息");
    console.log(buffer1);
    var model = { ChannelID: "12121", Content: buffer1 };
    var message = Message.create(model);//創建模型
    var buffer = Message.encode(message).finish();//轉成二進制
    console.log(buffer);

 運行頁面,對象已經被轉化了數組

這個時候可以用的WebSocket的send方法將對象發送到后端,但還可以根據和后端約定的協議對消息再做一次轉換。

解析:

  var decodeModel = Message.decode(buffer);
    console.log(decodeModel);
    console.log(Ut8ArrayToStr(decodeModel.Content));

拿到buffer之后再次轉化成我們的對象

這個時候需要將Uint8Array轉成字符串,才能直觀的獲得我們的Content中的內容。

function Ut8ArrayToStr(array) {
    var out, i, len, c;
    var char2, char3;

    out = "";
    len = array.length;
    i = 0;
    while (i < len) {
        c = array[i++];
        switch (c >> 4) {
            case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
                // 0xxxxxxx
                out += String.fromCharCode(c);
                break;
            case 12: case 13:
                // 110x xxxx   10xx xxxx
                char2 = array[i++];
                out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
                break;
            case 14:
                // 1110 xxxx  10xx xxxx  10xx xxxx
                char2 = array[i++];
                char3 = array[i++];
                out += String.fromCharCode(((c & 0x0F) << 12) |
                               ((char2 & 0x3F) << 6) |
                               ((char3 & 0x3F) << 0));
                break;
        }
    }
    return out;
}

這樣就完成整個過程。

小結:

實際開發中比上面介紹的要復雜,首先加載.proto對象是異步的,也就是說,在你使用WebSocket收發送消息的時候要確保已經獲得了模型,也就是例子中的Message對象。另外一個是兼容性處理。protobuf.js的兼容性如下:

比如ie8不支持,當然我們也不是要在IE8中使用protobuf.js,因為ie8也不支持WebSocket,我們可以用輪詢。是為了避免引入protobuf.js就會報錯,畢竟這個js有很多新瀏覽器對象。可以用typeof來阻止它在不支持的瀏覽器中運行。

//不支持WebSocket的 就不用初始化了
if (!window.WebSocket) return;
if (typeof exports=="undefined") return ;
        exports.writeFloatLE = writeFloat_ieee754.bind(null, writeUintLE);

同理,自己的js中也要判斷。

    function loadProto() {
        if (typeof protobuf == "undefined") return;//說明瀏覽器加載失敗
        protobuf.load("../xx.proto", function (err, root) {

這樣如果你有備用的輪詢通信方式,在ie8中也能運行起來了。

另外,Google官方也提供了JavaScript解析.proto文件的方式。

1. CommonJS-style imports (eg. `var protos = require('my-protos');`)
2. Closure-style imports (eg. `goog.require('my.package.MyProto');`)

closure-style的需要依賴goog,一大堆,而commonjs的示例更像是在node端的,在這個地方繞了一天,沒成功,最后選擇了protobuf.js的方式。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM