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
二、官方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
最后,
- 編寫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;
}
- 編寫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文件生成分析
參考:
一般每一個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.
智能推薦
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 是一種輕便高效的結構化數據存儲格式,可以用于結...
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...