Protobuf3 使用、入門教程及Demo

Protobuf簡介

​ 簡單設計協議, 通過自帶工具轉換成爲對應的語言代碼, 協議是二進制協議, 設計時只需要描述各個類的關係, 簡單明瞭

用法:

  • 設計協議是在fileName.proto文件中, 其中fileName是自己定義, 在通過protoc轉換成爲對應的代碼。

  • 關鍵字:

    • message 表示一個消息體, 相當於一個類。
    • 每個message中都有對應的變量, 每個變量有個對應的編號, 每個message內不同變量的編號不能重複。
    • 新版本的protobuf沒有了required, optional等說明關鍵字, 都默認爲optional
  • 基本語法

    //指定版本 使用protobuf3
    syntax = "proto3";
    
    message Account {
    	//賬號
    	uint64 ID = 1;
    	//名字
    	string name = 2;
    	//密碼
    	string password = 3;
    }
    

    ​ 語法很簡單, 上面例子就是指定使用protob3, 然後定義了一個Account類, 裏面包含ID, name, password, 對應的類型是 uint64, string, string。

    ​ 所以基本的語法規則跟C++類似。 只不過多了後面變量的編號。

  • 生成代碼:

    需要生成什麼語言的代碼需要直接指定,例如C++

    protoc --cpp_out=./ project.proto

    protoc是工具名, 可以直接運行的命令。

    --cpp_out是參數, 指定生成C++代碼, =後面指定生成的目錄。

    project.proto是定義的文件。

    一共會生成兩個文件。 project.pb.hproject.pb.cc

    其中有生成的Account類中有這幾個設置屬性的方法

    void clear_name();
    static const int kNameFieldNumber = 2;
    const std::string& name() const;
    void set_name(const std::string& value);
    void set_name(std::string&& value);
    void set_name(const char* value);
    void set_name(const char* value, size_t size);
    std::string* mutable_name();
    std::string* release_name();
    void set_allocated_name(std::string* name);
    
    // string password = 3;
    void clear_password();
    static const int kPasswordFieldNumber = 3;
    const std::string& password() const;
    void set_password(const std::string& value);
    void set_password(std::string&& value);
    void set_password(const char* value);
    void set_password(const char* value, size_t size);
    std::string* mutable_password();
    std::string* release_password();
    void set_allocated_password(std::string* password);
    
    // uint64 ID = 1;
    void clear_id();
    static const int kIDFieldNumber = 1;
    ::PROTOBUF_NAMESPACE_ID::uint64 id() const;
    void set_id(::PROTOBUF_NAMESPACE_ID::uint64 value);
    
    
    

    及get/set方法。

    可以直接操作該類的屬性。

  • 使用該代碼

    • 在要使用的代碼中包含此頭文件project.pb.h

      直接使用該對象即可。編譯的時候需要把project.pb.cc編譯, 並在鏈接的時候鏈接動態鏈接庫 libprotobuf.so

  • demo

    #include <iostream>
    #include <string>
    #include "project.pb.h"
    
    
    int main()
    {
    	Account account;
    	account.set_id(1000);
    	account.set_name("name");
    	account.set_password("password");
    
    	//序列化
    	std::string s = account.SerializeAsString();
    	if(s.size() == 0) {
    		std::cout << "error in SerializeAsString" << std::endl;
    	}
    	Account nAccount;
        //反序列化
    	if(nAccount.ParseFromString(s)) {
    		std::cout << nAccount.id() << std::endl;
    		std::cout << nAccount.name() << std::endl;
    		std::cout << nAccount.password() << std::endl;
    	} else {
    		std::cout << "error in ParseFromString" << std::endl;
    	}
    
    	return 0;
    }
    
  • 編譯

    project.pb.cc也需要編譯, 如果是工程中, 可以單獨編譯, 由於只有一個文件所以就放到一塊編譯了g++ demo.cpp project.pb.cc -lprotobuf -o main

    輸出結果爲:

    1000

    name

    password

更復雜的demo

  • message的嵌套

    message就像類一樣, 所以它也是可以嵌套的。

    可以直接在message內寫, 也可以在外部寫, 但是要注意的是, 一個message內的編號不能重複。

    所以令寫一個message會節省編號。

    節省編號的所有是節省空間。 前15號(0~15)用一個字節, 後面以此類推, 兩個三個字節, 所以前15編號比較珍貴。

  • demo

    //指定版本 使用protobuf3
    syntax = "proto3";
    
    message Account {
    	//賬號
    	uint64 ID = 1;
    	//名字
    	string name = 2;
    	//密碼
    	string password = 3;
    	//寵物狗
    	Dog dog = 4;
    }
    
    message Dog {
    	string name = 0;
    	bool sex = 1;
    }
    

    還有幾個比較重要的方法

    set_allocated_dog dog不是必須的, 是類的名字。 可以是其他的名字

    • 參數是一個對應類型的指針, 調用這個函數, 它會自動釋放這個指針的對象, 所以不需要delete, 否則會段錯誤。
    • 再次調用這個參數時, 如果之前已經設置過參數, 那麼再次調用的時候會之前設置的屬性刪除, 並且delete越來的對象。 在設置成新的屬性。

    除了這些方法之外還有一些clear之類的方法, 需要可以看文檔或者給的頭文件。

oneof

oneof 是設置多個屬性中的一個, 例如, 我的寵物可以是狗, 也可以是貓, 但是每個人只有一個的話。 設置兩個佔的空間就有點大。 因此只需要有一個就夠了, 所以這個oneof就像union一樣。

//指定版本 使用protobuf3
syntax = "proto3";

message Account {
	//賬號
	uint64 ID = 1;
	//名字
	string name = 2;
	//密碼
	string password = 3;
	//寵物
	oneof pet {
		Dog dog = 4;
		Cat cat = 5;
	}
}

message Dog {
	string name = 1;
	bool sex = 2;
}

message Cat {
	string name = 1;
	//屬性可以與Dog不同
}
  • 方法
    • has_cat 或者 has_dog 方法用於檢測是否有cat/dog
    • 添加cat和dog直接用原來的方法添加即可。 但是當添加dog的時候會自動刪除cat, 反之亦然。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章