protobuf-c的使用(二)使用

上一篇介紹了protobuf-c的構建。接下來介紹一下protobuf-c的使用。protobuf最核心的就是proto文件,其次通過protobuf-c編譯proto文件生成供c語言調用的庫文件和頭文件。下面逐一說明一下proto文件的定義、protobuf-c編譯以及c語言如何使用protobuf。

一、proto文件結構

protobuf以消息Message爲主要結構,消息中包含具體的字段,字段定義主要以required(必填字段)、optional(可選字段)、repeated(可重複字段)爲主,包含了各大編程語言的基本數據類型、引用類型等。具體定義參考如下:

  • .proto文件:包含了Message結構定義的協議文件,我們需要首先編寫.proto文件,然後再生成編程語言對應的源文件。

  • Message結構:包含了字段的,每一條字段都包含定義聲明、數據類型以及字段序號。字段序號是唯一不重複的,序號保證了不同語言和平臺的序列化和反序列化字段的字節順序。

  • 定義聲明: 

    • required:聲明該字段是必填字段。

    • optional:聲明該字段是可選字段。

    • repeated:聲明該字段是可重複字段,通常用數組表示,也可以是list。

  • 數據類型:protobuf支持的數據類型很全,可參考如下表:

.proto類型描述packc/c++類型
bool布爾類型pack(1)bool
double64位浮點類型pack(N)double
float32位浮點類型pack(N)float
int3232位整數類型pack(N)int
int6464位整數類型pack(N)__int64
uint32無符號32位整數類型pack(N)unsigned int
uint64無符號64位整數類型pack(N)unsigned __int64
sint3232位整數類型,使用可變長編碼方式。有符號的整型值。編碼時比通常的int32高效。pack(N)int
sint6464位整數類型 ,使用可變長編碼方式。有符號的整型值。編碼時比通常的int64高效。pack(1)__int64
fixed3232位無符號整數類型 ,總是4個字節。如果數值總是比總是比228大的話,這個類型會比uint32高效。pack(4)bool
fixed6464位無符號整數類型,總是8個字節。如果數值總是比總是比256大的話,這個類型會比uint64高效。pack(8)bool
sfixed3232位整數類型,總是4個字節。pack(4)bool
sfixed6464位整數類型,總是8個字節。pack(8)bool
string字符串類型pack(N)char*/char[]/std:string
bytes一個字符串必須是UTF-8編碼或者7-bit ASCII編碼的文本。pack(N)char*/char[]/std:string
enum用戶自定義枚舉類型pack(N)與 uint32相同bool
message用戶自定義的消息類型pack(N)struct/class

N 表示打包的字節並不是固定。而是根據數據的大小或者長度打包。

二、protobuf-c編譯proto文件

編譯命令:

 protoc-c --c_cout=. .proto文件 -lprotobuf-c

舉個栗子: 
定義消息Message Command(命令),其中包含字段:

  • 指令代碼:code 64位長整類型,用於區分指令。

  • 指令類型:type 32位整數類型,說明該指令是查詢(0)、讀寫(1)、調用執行(2)。

  • 調用模塊名:module 字符串,調用哪個模塊的模塊名稱。

  • 調用函數名:func 字符串,調用哪個模塊的函數名稱。

  • 調用函數參數:params 字符串數組,調用函數的參數。

.proto文件如下(Command.proto):

message Command{
        required sint64 code = 1; //指令代碼
        required sint32 type = 2; //指令類型 0 查詢 1 讀寫 2 調用執行
        required string module = 3; //調用模塊名
        required string func = 4; //調用函數名
        repeated string params = 5; //函數參數}

message CommandResponse{
        required sint32 code = 1; //返回代碼 0 成功 1 失敗
        optional string msg = 2; //返回消息 失敗消息或成功消息
        required sint32 version = 3; //接口版本
        repeated Command data = 4; //真正的數據字段}1234567891011121314

執行命令:

protoc-c --c_out=. Command.proto -lprotobuf-c

這裏寫圖片描述

可以看到生成了Command.pb-c.c和Command.pb-c.h的c語言源文件和頭文件。

三、c語言中使用protobuf

接下來嘗試調用上面生成的c文件。protobuf-c使用pack和unpack方法做序列化和反序列化操作。

在使用packed之前需要使用__INIT函數創建PB對象,然後爲對象中字段逐一賦值。

    CommandResponse response=COMMAND_RESPONSE__INIT;

這裏需要注意response中包含的Command,也需要使用__INIT函數進行初始化並賦值。

    Command command=COMMAND__INIT;

在逐一賦值後,我們需要分配一個buffer用於保存序列化字節,在對buffer分配空間時,可以使用__get_packed_size函數獲取PB結構體的大小作爲分配空間的大小。

    size_t size=command_response__get_packed_size(&response);

接下來使用__pack函數執行序列化操作。

    command_response__pack(&response,buf);

反序列化操作可直接使用__unpack函數。得到反序列化後的對象指針,通過指針可直接訪問PB中的字段。

    CommandResponse *response=
    command_response__unpack(NULL,size,buf);

在對PB訪問完成後,需要通過__free_unpacked來釋放反序列化的內存空間。

  command_response__free_unpacked(response, NULL);

具體例子可參考protobuf-c的github wiki:https://github.com/protobuf-c/protobuf-c/wiki/Examples


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章