• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • google protobuf (c++) 學習

    probuf是goole推出的微型RPC框架,這里記錄下安裝測試。
    參考文章:
    Google Protocol Buffers淺析(一)

    一、Ubuntu 18.04安裝 C++ Protocol

    首先參考官方README文檔進行安裝:
    前提

     sudo apt-get install autoconf automake libtool curl make g++ unzip
    

    當然可以在如下網站進行源碼下載離線安裝。
    https://github.com/protocolbuffers/protobuf/releases/latest
    這里通過git直接在終端進行安裝:

    $ git clone https://github.com/protocolbuffers/protobuf.git
    $ cd protobuf
    $ git submodule update --init --recursive
    $ ./autogen.sh
    
    $ ./configure
    $ make
    $ make check
    $ sudo make install
    $ sudo ldconfig # refresh shared library cache.
    

    默認安裝在/usr/local下面,可以進行查看庫文件。

    pkg-config --cflags protobuf         # print compiler flags
    pkg-config --libs protobuf           # print linker flags
    pkg-config --cflags --libs protobuf  # print both
    

    在這里插入圖片描述
    查看安裝版本:

     protoc --version
    

    pro

    二、官方examples代碼編譯測試

    參考官方examples

    通常,編寫一個protocol buffers應用需要經歷如下三步:

     1、定義消息格式文件,最好以proto作為后綴名
    
     2、使用Google提供的protocol buffers編譯器來生成代碼文件,一般為.h和.cc文件,主要是對消息格式以特定的語言方式描述
    
     3、使用protocol buffers庫提供的API來編寫應用程序  
    

    首先編寫addressbook.proto文件。

    // See README.txt for information and build instructions.
    //
    // Note: START and END tags are used in comments to define sections used in
    // tutorials.  They are not part of the syntax for Protocol Buffers.
    //
    // To get an in-depth walkthrough of this file and the related examples, see:
    // https://developers.google.com/protocol-buffers/docs/tutorials
    
    // [START declaration]
    syntax = "proto3";
    package tutorial;
    
    import "google/protobuf/timestamp.proto";
    // [END declaration]
    
    // [START java_declaration]
    option java_package = "com.example.tutorial";
    option java_outer_classname = "AddressBookProtos";
    // [END java_declaration]
    
    // [START csharp_declaration]
    option csharp_namespace = "Google.Protobuf.Examples.AddressBook";
    // [END csharp_declaration]
    
    // [START messages]
    message Person {
      string name = 1;
      int32 id = 2;  // Unique ID number for this person.
      string email = 3;
    
      enum PhoneType {
        MOBILE = 0;
        HOME = 1;
        WORK = 2;
      }
    
      message PhoneNumber {
        string number = 1;
        PhoneType type = 2;
      }
    
      repeated PhoneNumber phones = 4;
    
      google.protobuf.Timestamp last_updated = 5;
    }
    
    // Our address book file is just one of these.
    message AddressBook {
      repeated Person people = 1;
    }
    // [END messages]
    

    之后對其進行編譯,產生對應的xxx.pb.cc和xxx.pb.h文件。

    protoc -I=./ --cpp_out=./ addressbook.proto
    

    最后,

    1. 編寫add_person.cc文件,該應用程序實現控制臺輸入person的相關信息并寫入到文本文件:
    // See README.txt for information and build instructions.
    
    #include <ctime>
    #include <fstream>
    #include <google/protobuf/util/time_util.h>
    #include <iostream>
    #include <string>
    
    #include "addressbook.pb.h"
    
    using namespace std;
    
    using google::protobuf::util::TimeUtil;
    
    // 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;
        }
      }
      *person->mutable_last_updated() = TimeUtil::SecondsToTimestamp(time(NULL));
    }
    
    // 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;
    }
    
    1. 編寫list_people.cc文件,該應用程序實現將add_person.cc寫入的文本文件進行可視化讀取。
    // See README.txt for information and build instructions.
    
    #include <fstream>
    #include <google/protobuf/util/time_util.h>
    #include <iostream>
    #include <string>
    
    #include "addressbook.pb.h"
    
    using namespace std;
    
    using google::protobuf::util::TimeUtil;
    
    // 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.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;
            default:
              cout << "  Unknown phone #: ";
              break;
          }
          cout << phone_number.number() << endl;
        }
        if (person.has_last_updated()) {
          cout << "  Updated: " << TimeUtil::ToString(person.last_updated()) << 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;
    }
    

    分別進行編譯,產生對應的可執行文件

    c++ add_person.cc addressbook.pb.cc -o add_person_cpp `pkg-config --cflags --libs protobuf`
    c++ list_people.cc addressbook.pb.cc -o list_people_cpp `pkg-config --cflags --libs  protobuf`
    

    分別運行

    ./add_person_cpp address_book_file
    ./list_people_cpp address_book_file
    

    在這里插入圖片描述
    之后對寫入的文件進行讀取
    在這里插入圖片描述

    三、protobuf文件生成分析

    參考:

    Language Guide (proto3)
    C++ Generated Code

    一般每一個message對應生成一個類,枚舉型對應在高級語言中仍是一個枚舉型,值從0開始
    對于一個類型為string的變量,主要產生如下方法:

    // string number = 1;
      void clear_number();
      const std::string& number() const;
      void set_number(const std::string& value);
      void set_number(std::string&& value);
      void set_number(const char* value);
      void set_number(const char* value, size_t size);
      std::string* mutable_number();
      std::string* release_number();
      void set_allocated_number(std::string* number);
    

    具體分析參考引文的博主文章:

    可以看出,對于每個字段會生成一個has函數(has_number)、clear清除函數(clear_number)、set函數(set_number)、get函數(number和mutable_number)。這兒解釋下get函數中的兩個函數的區別,對于原型為const std::string &number() const的get函數而言,返回的是常量字段,不能對其值進行修改。但是在有一些情況下,對字段進行修改是必要的,所以提供了一個mutable版的get函數,通過獲取字段變量的指針,從而達到改變其值的目的。

    而對于字段修飾符為repeated的字段生成的函數,則稍微有一些不同,如phone字段,則編譯器會為其產生如下的代碼:

    // repeated .tutorial.Person.PhoneNumber phones = 4;
      int phones_size() const;
      void clear_phones();
      ::tutorial::Person_PhoneNumber* mutable_phones(int index);
      ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::tutorial::Person_PhoneNumber >*
          mutable_phones();
      const ::tutorial::Person_PhoneNumber& phones(int index) const;
      ::tutorial::Person_PhoneNumber* add_phones();
      const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::tutorial::Person_PhoneNumber >&
          phones() const;
    
    

    可以看出,set函數變成了add函數,這個其實很好理解。上面也說過,repeated修飾的字段在高級語言中的實現可能是個數組動態數組,所以當然通過添加的方式來加入新的字段值。而且get函數也變化很大,這個也不用多說了。

    另外,google protobuf提供了常用于調試輸出的函數

    virtual void CopyFrom(const Message & from); //Make this message int a copy of the given message.
    virtual void MergeFrom(const Message & from); //Merge the fields from the given message into this message.在這里插入圖片描述

    版權聲明:本文為u013457167原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/u013457167/article/details/91889611

    智能推薦

    Netty -08- Google Protobuf

    編碼和解碼的基本介紹 編寫網絡應用程序時,因為數據在網絡中傳輸的都是二進制字節碼數據,在發送數據時就需要編碼,接收數據 時就需要解碼 codec(編解碼器) 的組成部分有兩個:decoder(解碼器)和 encoder(編碼器)。encoder 負責把業務數據轉換成字節 碼數據,decoder 負責把字節碼數據轉換成業務數據 Netty 本身的編碼解碼的機制和問題分析 Netty 自身提供了一些 ...

    十一、Google Protobuf 編解碼

    Protobuf是一個靈活、高效、結構化的數據序列化框架,相比于XML等傳統的序列化工具,它更小、更快、更簡單。Protobuf支持數據結構化一次可以到處使用,甚至跨語言使用,通過代碼生成工具可以自動生成不同語言版本的源代碼,甚至可以在使用不同版本的數據結構進程間進行數據傳遞,實現數據結構的前向兼容。 一、Protobuf環境搭建 開發環境:Win10 64 bit; JDK 1.8; proto...

    google protobuf數據類型

    要通信,必須有協議,否則雙方無法理解對方的碼流。在protobuf中,協議是由一系列的消息組成的。因此最重要的就是定義通信時使用到的消息格式。   Protobuf消息定義 消息由至少一個字段組合而成,類似于C語言中的結構。每個字段都有一定的格式。 字段格式:限定修飾符① | 數據類型② | 字段名稱③ | = | 字段編碼值④ | [字段默認值⑤] ①.限定修飾符包含 required...

    《Dotnet9》系列-Google ProtoBuf在C#中的簡單應用

    簡介 什么是 Google Protocol Buffer? 假如您在網上搜索,應該會得到類似這樣的文字介紹: Google Protocol Buffer( 簡稱 Protobuf) 是 Google 公司內部的混合語言數據標準,目前已經正在使用的有超過 48,162 種報文格式定義和超過 12,183 個 .proto 文件。他們用于 RPC 系統和持續數據存儲系統。 Protocol Buf...

    【深度學習】筆記11:python caffe報錯:No module named google.protobuf.internal

    1:首先,安裝anaconda2 2:其次,再安裝protobuf-master 3:最后,再按照下面的介紹進行相應問題的解決,總之一句話,ubuntu16.04下的caffe的安裝和可視化環境都是沒問題的,不過在安裝過程中,有很多問題,需要一個問題一個問題的解決 解決ImportError: /home/douxiao/anaconda3/bin/../lib/libstdc++.so.6: v...

    猜你喜歡

    caffe源碼 數據結構 google protobuf

    caffe的數據結構,除了使用blob作為數據塊,大部分的數據結構都用proto文件來定義。 我們為表達網絡結構所寫prototxt文件就是protobuf讀取的文件,從其中,protobuf可以獲取層、參數的設置,反饋NetParameter、LayerParameter等重要初始化信息用于網絡、層的建立和設置。 caffe編譯時,第一個編譯的就是caffe.proto,它是所有文件的基礎。 什...

    使用CSharp編寫Google Protobuf插件

    什么是 Google Protocol Buffer? Google Protocol Buffer( 簡稱 Protobuf) 是 Google 公司內部的混合語言數據標準,目前已經正在使用的有超過 48,162 種報文格式定義和超過 12,183 個 .proto 文件。他們用于 RPC 系統和持續數據存儲系統。 Protocol Buffers 是一種輕便高效的結構化數據存儲格式,可以用于結...

    HTML中常用操作關于:頁面跳轉,空格

    1.頁面跳轉 2.空格的代替符...

    freemarker + ItextRender 根據模板生成PDF文件

    1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...

    電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!

    Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...

    精品国产乱码久久久久久蜜桃不卡