protobuf篇介紹、安裝、測試

      網友投稿 1684 2025-04-01

      愿打開此篇對你有所幫助。


      @[toc]

      關于 Protobuf3 的介紹,有前輩整理了,我就偷個懶:Protobuf3詳細介紹

      PB、JSON、XML

      綜上所述目前最好的設計消息數據包方式是服務器和客戶端通信協議推薦用protobuf,服務器存入數據庫時用json。

      安裝

      工欲善其事,必先利其器。

      1、從github上下載自己所需版本:https://github.com/protocolbuffers/protobuf/releases/ 2、解壓 3、進入目錄 4、./configure 5、make && make install 6、vi /etc/profile,追加一下內容:

      #(動態庫搜索路徑) 程序加載運行期間查找動態鏈接庫時指定除了系統默認路徑之外的其他路徑 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/protobuf/lib/ #(靜態庫搜索路徑) 程序編譯期間查找動態鏈接庫時指定查找共享庫的路徑 export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/protobuf/lib/ #執行程序搜索路徑 export PATH=$PATH:/usr/local/protobuf/bin/ #c程序頭文件搜索路徑 export C_INCLUDE_PATH=$C_INCLUDE_PATH:/usr/local/protobuf/include/ #c++程序頭文件搜索路徑 export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/usr/local/protobuf/include/ #pkg-config 路徑 export PKG_CONFIG_PATH=/usr/local/protobuf/lib/pkgconfig/

      7、vi /etc/ld.so.conf,追加/usr/local/protobuf/lib 8、/sbin/ldconfig -v 9、protoc --version

      如何寫一個PB文件

      也有proto3,都可以吧,我最開始接觸的是2,就翻譯 2 吧。

      官網地址:https://developers.google.cn/protocol-buffers/docs/proto,有興趣的朋友可以自行查閱。

      好吧,建議自己打開看,我不全翻譯,就看到一些覺得比較重要的我搬過來。

      Protobuf消息定義

      你首先需要在一個 .proto 文件中定義你需要做串行化的數據結構信息。每個ProtocolBuffer信息是一小段邏輯記錄,包含一系列的鍵值對。

      消息由至少一個字段組合而成,類似于C語言中的結構。每個字段都有一定的格式。

      字段格式:限定修飾符① | 數據類型② | 字段名稱③ | = | 字段編碼值④ | [字段默認值⑤]

      這里有個非常簡單的 .proto 文件定義了個人信息:

      message Person { required string name=1; required int32 id=2; optional string email=3; enum PhoneType { MOBILE=0; HOME=1; WORK=2; } message PhoneNumber { required string number=1; optional PhoneType type=2 [default=HOME]; } repeated PhoneNumber phone=4; }

      Required: 表示是一個==必須字段==,必須相對于發送方,在發送消息之前必須設置該字段的值,對于接收方,必須能夠識別該字段的意思。發送之前沒有設置required字段或者無法識別required字段都會引發編解碼異常,==導致消息被丟棄==。

      Optional:表示是一個==可選字段==,可選對于發送方,在發送消息時,可以有選擇性的設置或者不設置該字段的值。對于接收方,如果能夠識別可選字段就進行相應的處理,==如果無法識別,則忽略該字段==,消息中的其它字段正常處理。—因為optional字段的特性,很多接口在升級版本中都==把后來添加的字段都統一的設置為optional字段==,這樣老的版本無需升級程序也可以正常的與新的軟件進行通信,只不過新的字段無法識別而已,因為并不是每個節點都需要新的功能,==因此可以做到按需升級和平滑過渡==。

      Repeated:表示該字段可以包含0~N個元素。其特性和optional一樣,但是每一次可以包含多個值。==可以看作是在傳遞一個數組的值==。

      Protobuf定義了一套基本數據類型。幾乎都可以映射到C++\Java等語言的基礎數據類型.

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

      關于message,類似于C語言中的結構包含另外一個結構作為數據成員一樣。

      編碼值的取值范圍為 1~2^32(4294967296)。

      不信往上面翻翻看,看看是不是都是數值。

      ==其中 1~15的編碼時間和空間效率都是最高的==,編碼值越大,其編碼的時間和空間效率就越低(相對于1-15),當然一般情況下相鄰的2個值編碼效率的是相同的,除非2個值恰好實在4字節,12字節,20字節等的臨界區。比如15和16.

      ==1900~2000編碼值為Google protobuf 系統內部保留值,建議不要在自己的項目中使用==。

      protobuf 還建議把經常要傳遞的值把其字段編碼設置為1-15之間的值。

      protobuf篇:介紹、安裝、測試

      消息中的字段的編碼值無需連續,只要是合法的,并且==不能在同一個消息中有字段包含相同的編碼值==。

      當在傳遞數據時,對于required數據類型,如果用戶沒有設置值,則使用默認值傳遞到對端。當接受數據是,對于optional字段,如果沒有接收到optional字段,則設置為默認值。

      幾個注意事項

      protobuf 接口文件可以像C語言的h文件一樣,分離為多個,在需要的時候通過 import導入需要的文件。

      雖然可以在單個.proto文件中定義多種消息類型(例如消息,枚舉和服務),但當在單個文件中定義大量具有不同依賴性的消息時,也

      可能導致依賴性膨脹。建議每個.proto文件包含盡可能少的消息類型。

      避免名稱沖突,可以給每個文件指定一個package名稱,對于C++解析為名稱空間。

      記得在開頭加上這兩句:

      syntax = "proto3"; package demo;

      枚舉的定義和C++相同,但是有一些限制。

      枚舉值必須大于等于0的整數。

      使用分號(;)分隔枚舉變量而不是C++語言中的逗號(,)

      編譯PB

      可編譯文件

      首先,你要有一個PB文件可以拿去編譯,我知道你多半也沒有,沒事我這里有。

      syntax = "proto3"; package demo; message Person { string name = 1; int32 id = 2; string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { string number = 1; PhoneType type = 2; } repeated PhoneNumber phone = 4; }

      開始編譯

      我下載了好多款,不過主語言是C++,畢竟打開一次不容易。打不開下載目錄的小伙伴可以私信我拿。

      打開cmd, cd到該目錄,protoc.exe的命令行參數格式如下:

      protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR path/to/file.proto

      編譯之后就會出現新的文件了。

      閱覽文件

      打開之后太長了,自己去看。我這里提幾點。

      (1)proto中的package在C++中是namespace; (2)proto中的message在C++中是class,類里面有各個成員的set/get;基類是google::protobuf::Message。 (3)代碼中可以看見C++11中的移動構造和移動賦值函數。

      搞技術的人不搞那些彎彎繞的,放碼過來吧。

      放碼過來

      proto

      syntax = "proto2"; package tutorial; message Person { optional string name = 1; optional int32 id = 2; optional string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { optional string number = 1; optional PhoneType type = 2 [default = HOME]; } repeated PhoneNumber phones = 4; } message AddressBook { repeated Person people = 1; }

      讀.cpp

      #include #include #include #include "person.pb.h" using namespace std; // This function fills in a Person message based on user input. void PromptForAddress(tutorial::Person* person) { cout << "Enter person ID number: "; int id; cin >> id; person->set_id(id); cin.ignore(256, '\n'); cout << "Enter name: "; getline(cin, *person->mutable_name()); cout << "Enter email address (blank for none): "; string email; getline(cin, email); if (!email.empty()) { person->set_email(email); } while (true) { cout << "Enter a phone number (or leave blank to finish): "; string number; getline(cin, number); if (number.empty()) { break; } tutorial::Person::PhoneNumber* phone_number = person->add_phones(); phone_number->set_number(number); cout << "Is this a mobile, home, or work phone? "; string type; getline(cin, type); if (type == "mobile") { phone_number->set_type(tutorial::Person::MOBILE); } else if (type == "home") { phone_number->set_type(tutorial::Person::HOME); } else if (type == "work") { phone_number->set_type(tutorial::Person::WORK); } else { cout << "Unknown phone type. Using default." << endl; } } } // Main function: Reads the entire address book from a file, // adds one person based on user input, then writes it back out to the same // file. int main(int argc, char* argv[]) { // Verify that the version of the library that we linked against is // compatible with the version of the headers we compiled against. GOOGLE_PROTOBUF_VERIFY_VERSION; if (argc != 2) { cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl; return -1; } tutorial::AddressBook address_book; { // Read the existing address book. fstream input(argv[1], ios::in | ios::binary); if (!input) { cout << argv[1] << ": File not found. Creating a new file." << endl; } else if (!address_book.ParseFromIstream(&input)) { cerr << "Failed to parse address book." << endl; return -1; } } // Add an address. PromptForAddress(address_book.add_people()); { // Write the new address book back to disk. fstream output(argv[1], ios::out | ios::trunc | ios::binary); if (!address_book.SerializeToOstream(&output)) { cerr << "Failed to write address book." << endl; return -1; } } // Optional: Delete all global objects allocated by libprotobuf. google::protobuf::ShutdownProtobufLibrary(); return 0; }

      寫.cpp

      #include #include #include #include "addressbook.pb.h" using namespace std; // Iterates though all people in the AddressBook and prints info about them. void ListPeople(const tutorial::AddressBook& address_book) { for (int i = 0; i < address_book.people_size(); i++) { const tutorial::Person& person = address_book.people(i); cout << "Person ID: " << person.id() << endl; cout << " Name: " << person.name() << endl; if (person.has_email()) { cout << " E-mail address: " << person.email() << endl; } for (int j = 0; j < person.phones_size(); j++) { const tutorial::Person::PhoneNumber& phone_number = person.phones(j); switch (phone_number.type()) { case tutorial::Person::MOBILE: cout << " Mobile phone #: "; break; case tutorial::Person::HOME: cout << " Home phone #: "; break; case tutorial::Person::WORK: cout << " Work phone #: "; break; } cout << phone_number.number() << endl; } } } // Main function: Reads the entire address book from a file and prints all // the information inside. int main(int argc, char* argv[]) { // Verify that the version of the library that we linked against is // compatible with the version of the headers we compiled against. GOOGLE_PROTOBUF_VERIFY_VERSION; if (argc != 2) { cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl; return -1; } tutorial::AddressBook address_book; { // Read the existing address book. fstream input(argv[1], ios::in | ios::binary); if (!address_book.ParseFromIstream(&input)) { cerr << "Failed to parse address book." << endl; return -1; } } ListPeople(address_book); // Optional: Delete all global objects allocated by libprotobuf. google::protobuf::ShutdownProtobufLibrary(); return 0; }

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:華為云與阿里云使用心得
      下一篇:業務流程管理流程:如何優化和提升企業流程效率
      相關文章
      亚洲欧洲第一a在线观看| 亚洲乱妇老熟女爽到高潮的片| 亚洲中文字幕乱码一区| 亚洲av无码乱码国产精品| vvvv99日韩精品亚洲| 日韩精品亚洲专区在线影视| 日本亚洲欧美色视频在线播放| 亚洲伊人久久大香线蕉AV| 亚洲情A成黄在线观看动漫软件| 亚洲综合色7777情网站777| 亚洲AV无码乱码麻豆精品国产| 亚洲图片激情小说| 亚洲国产成人精品久久| 精品亚洲AV无码一区二区 | 亚洲女人影院想要爱| 亚洲狠狠狠一区二区三区| 亚洲国语在线视频手机在线| 亚洲精品视频观看| 亚洲一区动漫卡通在线播放| 亚洲日本乱码卡2卡3卡新区| 亚洲七久久之综合七久久| 亚洲精品无AMM毛片| 风间由美在线亚洲一区| 亚洲人成网站18禁止一区| 久久亚洲精品无码观看不卡| 亚洲日韩中文无码久久| 亚洲AV无码乱码国产麻豆穿越| 亚洲AV日韩AV天堂久久| 亚洲欧洲精品久久| 亚洲国产日韩精品| 亚洲av永久无码一区二区三区| 风间由美在线亚洲一区| 区三区激情福利综合中文字幕在线一区亚洲视频1| 无码一区二区三区亚洲人妻| 久久精品国产亚洲一区二区三区| 亚洲夜夜欢A∨一区二区三区| 亚洲国产一区国产亚洲| 亚洲三级在线播放| 日韩欧美亚洲中文乱码| 亚洲中文字幕无码永久在线| 亚洲国产精品自在线一区二区|