日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

protobuf流的反解析Message

發布時間:2024/4/11 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 protobuf流的反解析Message 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

0x01 protobuf的基本概念


protobuf通過定義".proto"文件來描述數據的結構。.proto文件中用"Message"所表示所需要序列化的數據的格式。Message由field組成,Field類似Java或者C++中成員變量,通常一個field的定義包含修飾符、類型、名稱和ID。下面看一個簡單的.proto文件的例子:


[plain]?view plaincopy
  • package?testInfo;??
  • message?Chats???
  • {??
  • ????optional?string?content1?=?1;??
  • ????required?int32?content2?=?2;??
  • ??????
  • ????message?EmbMsg??
  • ????{??
  • ????????optional?string?a?=?1;??
  • ????}??
  • ????repeated?EmbMsg?a?=?3;??
  • }??
  • 然后利用protoc工具生成.h和.cpp文件,并且編寫代碼

    [cpp]?view plaincopy
  • testInfo::Chats?chatTest;??
  • chatTest.set_content1("hello");??
  • chatTest.set_content2(32);??
  • testInfo::Chats::EmbMsg?*pMsg?=?chatTest.add_a();??
  • pMsg->set_a("aaaa");??
  • pMsg?=?chatTest.add_a();??
  • pMsg->set_a("bbb");??
  • std::string?outputStr;??
  • chatTest.SerializeToString(&outputStr);??
  • printf("str?%s",?outputStr.c_str());??
  • 得到十六進制流數據為:

    [plain]?view plaincopy
  • 0x00DE94C8??0a?05?68?65?6c?6c?6f?10?20?1a?06?0a?04?61?61?61??..hello.?....aaa??
  • 0x00DE94D8??61?1a?05?0a?03?62?62?62??

  • 0x02 ?protobuf流的反解析


    2.1 ?Varint編碼


    Protobuf的二進制使用Varint編碼。Varint 是一種緊湊的表示數字的方法。它用一個或多個字節來表示一個數字,值越小的數字使用越少的字節數。這能減少用來表示數字的字節數。


    Varint 中的每個 byte 的最高位 bit 有特殊的含義,如果該位為 1,表示后續的 byte 也是該數字的一部分,如果該位為 0,則結束。其他的 7 個 bit 都用來表示數字。因此小于 128 的數字都可以用一個 byte 表示。


    例如:十六進制流里面其中兩個字節:0x95 0x01,則其轉換運算為:(0x95 & 0x7F) ?| (0x01 << 0x7) = 0x5 | 0x80 = 0x95。

    若其中四個字節:0x9D 0xF4 0xC1 0xCB 0x05,則其轉換運算為:

    (0x9D & 0x7F) | (0xF4 & 0x7F)<<7 | (0xC1 & 0x7F)<<E | (0xCB & 0x7F)<<0x15 | 05<<0x1C?

    =?1D | 3A00 | 104000 | 9600000 | 50000000?

    = 59707A1D


    2.2 數值類型


    Protobuf經序列化后以二進制數據流形式存儲,這個數據流是一系列key-Value對。Key用來標識具體的Field,在解包的時候,Protobuf根據 Key 就可以知道相應的 Value 應該對應于消息中的哪一個 Field。

    Key 的定義如下:

    (field_number << 3) | wire_type

    Key由兩部分組成。第一部分是 field_number,比如消息chatTest.content1中 的 field_number 為 1。第二部分為 wire_type。表示 Value 的傳輸類型。Wire Type 可能的類型如下表所示:

    typeMeaningUsed For
    0Varintint32, int64, uint32, uint64, sint32, sint64, bool, enum
    164-bitfixed64, sfixed64, double
    2Length-delimistring, bytes, embedded messages, packed repeated fields
    3Start groupGroups (deprecated)
    4End groupGroups (deprecated)
    532-bit fixed32, sfixed32, float
    ???

    以上面生成的十六進制流我們可以開始分析

    required和optional不會有任何字節來表示這個修飾符。

    repeated會存在相同的field_number。

    [plain]?view plaincopy
  • 0a?05??
  • 0A -> field_num=1, type=2;

    05 -> 代表字符串長度05


    [plain]?view plaincopy
  • 68?65?6c?6c?6f??
  • -> "hello"


    [plain]?view plaincopy
  • 10?20??
  • 10->field_num=2, type=0;

    20->value=0x20;

    [plain]?view plaincopy
  • 1a?06?0a?04?61?61?61?61?1a?05?0a?03?62?62?62??
  • 1a->field_num=3, type=2;

    06->結構體長度06

    0a->field_num=1,type=2;

    04->字符串長度04

    61 61 61 61 ->value="aaaa"

    1a->field_num=3, type=2;
    05->結構體長度05

    0a->field_num=1,type=2;

    03->字符串長度03

    61 61 61 61 ->value="bbb"


    2.3 protoc 進行反序列化


    上面的步驟是手動解析的過程,而利用google提供的工具可以幫助我們自動化的解析以上過程,在面對復雜的protobuf結構的時候能達到事半功倍的效果。按下面步驟來做:

    首先配置java環境

    其次安裝jython,這里

    然后編寫Python腳本,protobuf.py

    [python]?view plaincopy
  • import?subprocess??
  • def?decode(data):??
  • ????process?=?subprocess.Popen([r'D:\protobuf\protoc.exe',?'--decode_raw'],??
  • ????stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)??
  • ??
  • ????output?=?error?=?None??
  • ????try:??
  • ????????output,?error?=?process.communicate(data)??
  • ????except?OSError:??
  • ????????pass??
  • ????finally:??
  • ????????if?process.poll()?!=?0:??
  • ????????????process.wait()??
  • ????return?output??
  • ??
  • f?=?open(r"D:\testprotobuf.bin",?"rb")??
  • data?=?f.read()??
  • print?'data:/n',decode(data)??
  • f.close()??

  • 其中testprotobuf.bin是我們的protobuf流文件。

    最后運行腳本

    [plain]?view plaincopy
  • C:\Users\Administrator>cd?C:\jython2.7.0??
  • ??
  • C:\jython2.7.0>java?-jar?jython.jar?D:\task\qq-ups\protobuf.py??
  • data:/n?1:?"hello"??
  • 2:?32??
  • 3?{??
  • ??1:?"aaaa"??
  • }??
  • 3?{??
  • ??1:?"bbb"??
  • }??
  • 利用反序列化的結構來推測.proto的message的結構及每個字段的含義,就能達到protobuf流反解析的目的了。

    上述方案是采用python調用protoc的命令,由于protobuf是開源的,是在牛逼可以看他的源碼,看他怎么解析出來的,我看了下他的源碼,由于太菜和項目時間比較緊,每太看明白,暫時采用上述方法。

    總結

    以上是生活随笔為你收集整理的protobuf流的反解析Message的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。