protobuf 中的巢狀訊息的使用

2021-09-08 01:12:20 字數 3514 閱讀 8673

protobuf的簡單的使用,不過還留下了乙個問題,那就是之前主要介紹的都是對簡單資料的賦值,簡單資料直接採用set_xx()即可,但是如果不是簡單變數而是自定義的復合型別變數,就沒有簡單的set函式呼叫了,下面看乙個簡單的例子。

在網路遊戲中,遊戲玩家之間的同步是乙個最基本的功能,而同步是通過對座標的廣播進行的,因此我們假設乙個簡單的模型,當乙個玩家的位置發生變化時,將玩家的新位置發給地圖內所有玩家,根據這個情況寫出以下proto檔案。

message playerpos
這樣就有乙個問題,現在的遊戲都是3d遊戲,因此需要xyz來表示位置,還需要另一組xyz來表示朝向,如果用簡單變數的話就會顯的很亂,而且無論是位置還是朝向其實都是一組xyz,因此可以將xyz抽出來成為乙個復合資料型別,單獨放在乙個檔案中。這樣就構成以下檔案。

file  vector.proto

message vector3d;

file player.proto

import "vector.proto";

message playerpos ;

編譯的時候先編譯vector檔案,採用import時需要注意路徑,本例中兩檔案在同一目錄下。

protoc --cpp_out=.  vector.proto  player.proto

proto對應的檔案已經生成了,但是該怎麼賦值呢,查api查了半天有點不知所以,乾脆來看生成的類檔案的源**吧

// required uint32 playerid = 1;

inline bool has_playerid() const;

inline void clear_playerid();

static const int kplayeridfieldnumber = 1;

inline ::google::protobuf::uint32 playerid() const;

inline void set_playerid(::google::protobuf::uint32 value);

// required .vector3d pos = 2;

inline bool has_pos() const;

inline void clear_pos();

static const int kposfieldnumber = 2;

inline const ::vector3d& pos() const;

inline ::vector3d* mutable_pos();

inline ::vector3d* release_pos();

inline void set_allocated_pos(::vector3d* pos);

上面列出了生成的部分源**,主要是playerpos的操作變數的函式,第乙個playid很簡單,可以看到直接使用set_playerid ( ) 即可,但是對於巢狀的pos 發現沒有對應的set_pos方法,不過發現了乙個set_allocated_pos() 函式,這個函式也是set開頭的,看看這個函式是幹嘛的。

inline void playerpos::set_allocated_pos(::vector3d* pos)  else 

}

看上去可以賦值,直接呼叫set_allocated_pos() 進行賦值看一看

playerpos player;

vector3d tmp;

tmp.x = 1;

tmp.y = 2;

tmp.z = 3;

player.set_allocated_pos(&tmp)

編譯沒問題,但是執行時出現錯誤,而且是很奇怪的錯誤,仔細了檢視一下playerpos的原始碼,發現乙個問題

::vector3d* pos_;

::google::protobuf::uint32 playerid_;

上面是playerpos中變數的儲存形式,發現pos是作為乙個指標儲存的,如果按照之前的賦值 tmp 是乙個區域性變數,函式返回時區域性變數自動銷毀,而pos_儲存的仍然是已被銷毀的tmp的位置,因此會出錯,如果採用new的話就可以解決這個問題,即賦值方法如下

playerpos player;

vector3d *tmp = new vector3d;

tmp->x = 1;

tmp->y = 2;

tmp->z = 3;

player.set_allocated_pos(tmp)

這樣即可,編譯執行都沒有問題。

如此之外,還有一種賦值方法,就是呼叫mutable_pos()

inline ::vector3d* playerpos::mutable_pos()

mutable_pos () 中自己new出了乙個vector3d 物件,而vector3d中又實現了賦值的過載,因此可以這樣解決

playerpos player;

vector3d *tmp = player.mutable_pos();

tmp->x = 1;

tmp->y = 2;

tmp->z = 3;

(六)ProtoBuf訊息巢狀

我們在各種語言開發中類的定義是可以互相巢狀的,也可以使用其他類作為自己的成員屬性型別。在protobuf中同樣支援訊息巢狀,可以在乙個訊息中巢狀另外乙個訊息,字段型別可以是另外乙個訊息型別。定義result訊息 message result 定義searchresponse訊息 message se...

Protobuf的自動反射訊息型別的方法

1.每個訊息頭部中帶上type name,作為訊息的型別標識 2.通過type name可以找到描述符descriptor findmessagetypebyname 3.通過描述符descriptor 建立乙個對應type name的物件,再用訊息的payload去初始化這個訊息物件 4.具現化i...

protobuf中的omitempty欄位

一句話總結 帶有omitempty欄位的成員,如果該字段為nil 字串 空陣列等 則打包的json結果不會有這個字段。我們把proto檔案自動生成go 時會出現omitempty欄位,如下 type reply struct直接上 package main import encoding json ...