【c++】14.编译proto和proto相关用法
編譯proto和proto相關用法
關于proto相關的知識可以參考系列博客 https://blog.csdn.net/daaikuaichuan/category_9869251.html
【xx.proto文件中如果要注釋的話,注釋符號也是雙斜杠"//"】
1.編譯proto的問題
重裝protoc可參考 https://blog.csdn.net/u013498583/article/details/74231058
查看當前protoc版本: protoc --version
查看protoc安裝位置:which protoc
查找protoc相關文件:sudo find / -name protoc
編譯proto文件
protoc caffe.proto --cpp_out=./ 生成caffe.pb.h、caffe.pb.cc文件
protoc caffe.proto --python_out=./ 生成caffe_pb2.py文件
假如環境中裝了一個以上的protoc版本,可使用protoc雙擊tab鍵,會彈出所有版本(protoc protoc_2.6.1,其中protoc是默認版本,protoc --version是查看當前默認protoc版本)。
如果我們要使用非默認版本protoc編譯proto,可以protoc_2.6.1 caffe.proto --cpp_out=./這種方式編譯。
在編譯MobileNet-YOLO工程時,使用protoc protoc_2.6.1編譯后的 caffe.pb.h 、caffe.pb.cc 文件粘貼到 caffe\include\caffe\proto即可。
----------------------------------------------------------------------------------------
2.proto相關函數用法
如果有一個proto_name結構的 proto消息:
2.1 set_xx(value)、 add_xx()、 mutable_xxx()
proto_name.set_xx(value) 該函數給對應的變量賦值
proto_name.add_xx() 該函數給對應的repeated變量增加一個xx類型的元素,返回值為指針類型。一般用法為:在for循環中調用一次,proto消息就添加一個該類型數據。
proto_name.mutable_xxx() 該函數返回指向該字段的一個指針,同時將該字段置為被設置狀態。若該對象存在,則直接返回該對象,若不存在則新new 一個。
----------------------------------------------------------------------------------------
2.2 SerializeToString、ParseFromString、SerializeToArray、ParseFromArray、CopyFrom、IsInitialized、
例如,有 proto_name.proto文件,把這個 proto_name.proto文件編譯后,會產生 proto_name.pb.h 和 proto_name.pb.cc, 生成的.h文件中的class都繼承自::google::protobuf::Message類,Message類提供了一些方法可以檢查或者操作整個message,包括:
bool IsInitialized() const; 檢查是否所有required變量都已經初始化;
string DebugString() const; 返回message的可閱讀的表示,主要用于調試程序;
void CopyFrom(const Person& from); 使用一個message的值覆蓋本message;
void Clear(); 清空message的所有成員變量值。
----------------------------------------------------------------------------------------
每個message類都提供了寫入和讀取message數據的方法,包括
bool SerializeToString(string* output) const; // 把message編碼進output。
bool ParseFromString(const string& data); // 從string解碼到message
bool SerializeToArray(char* buf,int size) const; // 把message編碼進數組buf.
bool ParseFromArray(const char* buf,int size); // 把 buf解碼到message。此解碼方法效率較ParseFromString高很多,所以一般用這種方法解碼。
bool SerializeToOstream(ostream* output) const; // 把message編碼進ostream
bool ParseFromIstream(istream* input); // 從istream解碼到message
備注:發送接收端所使用的加碼解碼方法不一定非得配對,即發送端用SerializeToString 接收端不一定非得用ParseFromString ,可以使用其他解碼方法。
----------------------------------------------------------------------------------------
一般使用 bool SerializeToString(string* output) const; 和 bool SerializeToArray(char* buf,int size) const;
例如當需要使用tcp/udp發送包含數組的時候,建議使用 bool SerializeToArray(char* buf,int size) const;,因為涉及到 數據包頭、校驗位之類的需要使用數組索引的方式,這樣最好使用SerializeToArray。
#define _fill_pack(name) \{ \char tbuf[256 * 1024]; \uint32_t len = name.ByteSize(); \auto header = name.header(); \_fill_pack_head(static_cast<uint32_t>(netproxy_##name##_pack), len, \reinterpret_cast<netproxy_pack_t *>(tbuf)); \if (!name.SerializeToArray(&tbuf[sizeof(netproxy_pack_t)], len)) { \SERROR << "serialize error, name:" << #name << " len:" << len; \len = -sizeof(netproxy_pack_t); \} \Send_data(tbuf, len + sizeof(netproxy_pack_t), netproxy_##name##_pack); \}其他時候可以直接使用SerializeToString。
----------------------------------------------------------------------------------------
用法1:對外接口的消息結構的兼容性
當某個對外接口的消息結構 msgA 中的某個變量的結構總是要根據需求而頻繁增刪修改的時候,一般會在這個消息結構 msgA 中定義一個std::string proto_data的變量,
這樣只需要修改proto_name.proto文件中的內容,而不需要總是修改 msgA(尤其是當修改msgA可能需要修改框架協議的時候,總之就是代價比較大),使用proto方法來解決這個問題就特別方便。
原始結構:
struct msgA{MsgHeader header;bool is_ok;structBBB msgbbb; //當這個結構體 structBBB 增刪修改結構比較麻煩時,會造成頻繁修改對外接口 msgA 的麻煩。 }方法:
先定義一個 proto_name.proto文件,把這個 proto_name.proto文件編譯后,會產生 proto_name.pb.h和 proto_name.pb.cc,
對其中定義的變量賦值是使用 set_xxx(111) 函數進行賦值,賦值完成后再序列化之后進行打包發送;
發送之前使用 proto_name.SerializeToString(&data) 把該 結構序列化為string類型,然后再發送。
原始結構 修改為:
下面的函數,我們封裝了proto自帶的SerializeToString和ParseFromString方法
// msg轉換成string template <class T> void MsgToString(const T msg, std::string &data) {msg.SerializeToString(&data); } // 將string轉換成msg template <class T> void StringToMsg(const std::string data, T &msg) {msg.ParseFromString(data); }----------------------------------------------------------------------------------------
用法2:
當我們需要使用配置文件來給許多變量進行賦值的時候,就可以把這些變量全都定義在 config.proto中,然后建立一個config.pb.txt文件,在config.pb.txt文件中對config.proto中的變量進行設置。
后續進行一些讀取config.pb.txt文件中的內容,然后需要的地方獲取這些內容。
代碼涉及到文件讀取解析proto等等的內容,詳解見下:
上面這個函數調用下面這兩個函數:
函數1: 讀取二進制文件,調用了proto定義的內置函數 bool ParseFromIstream(istream* input)
bool GetProtoFromBinaryFile(const std::string &file_name,google::protobuf::Message *message) {std::fstream input(file_name, std::ios::in | std::ios::binary);if (!input.good()) {SERROR << "Failed to open file " << file_name << " in binary mode.";return false;}if (!message->ParseFromIstream(&input)) {SERROR << "Failed to parse file " << file_name << " as binary proto.";return false;}return true; }函數2: 讀取ASCII文件,調用了open(),close()和proto內置函數static bool Parse(io::ZeroCopyInputStream* input, Message* output);
bool GetProtoFromASCIIFile(const std::string &file_name,google::protobuf::Message *message) {using google::protobuf::TextFormat;using google::protobuf::io::FileInputStream;using google::protobuf::io::ZeroCopyInputStream;int file_descriptor = open(file_name.c_str(), O_RDONLY);if (file_descriptor < 0) {SERROR << "Failed to open file " << file_name << " in text mode.";// Failed to open;return false;}ZeroCopyInputStream *input = new FileInputStream(file_descriptor);bool success = TextFormat::Parse(input, message);if (!success) {SERROR << "Failed to parse file " << file_name << " as text proto.";}delete input;close(file_descriptor);return success; }總結
以上是生活随笔為你收集整理的【c++】14.编译proto和proto相关用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【c++】9.深拷贝、浅拷贝、拷贝构造函
- 下一篇: 【c++】10. memset()、【s