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