官方文档

什么是 protocol buffer?

Protocol buffers are a flexible, efficient, automated mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages. You can even update your data structure without breaking deployed programs that are compiled against the "old" format.

protocol buffers 是一种用于序列化结构化数据的灵活,高效,自动化的机制–以XML为例,但更小,更快,更简单。 您定义要一次构造数据的方式,然后可以使用生成的特殊源代码轻松地使用各种语言在各种数据流中写入和读取结构化数据。 您甚至可以更新数据结构,而不会破坏已针对“旧”格式编译的已部署程序。

如何工作?

通过在.proto文件中定义协议缓冲区消息类型,您可以指定要序列化的信息的结构。 每个protocol buffer消息都是一个小的逻辑信息记录,其中包含一系列name-value对。 这是.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;
}

每种消息类型都有一个或多个唯一编号的字段,并且每个字段都有一个名称和一个值类型。您可以指定可选字段,必填字段和重复字段。

定义消息后,就可以在.proto文件上为应用程序的语言运行protocol buffer编译器,以生成数据访问类。

如果选择的语言是C++,则上面的示例将生成一个名为Person的类。 然后,您可以在应用程序中使用此类来填充,序列化和检索Person消息。 然后,您可以编写如下代码:

// encode
Person person;
person.set_name("John Doe");
person.set_id(1234);
person.set_email("jdoe@example.com");
fstream output("myfile", ios::out | ios::binary);
person.SerializeToOstream(&output); // decode
fstream input("myfile", ios::in | ios::binary);
Person person;
person.ParseFromIstream(&input);
cout << "Name: " << person.name() << endl;
cout << "E-mail: " << person.email() << endl;

关于 proto3

Our most recent version 3 release introduces a new language version - Protocol Buffers language version 3 (aka proto3), as well as some new features in our existing language version (aka proto2). Proto3 simplifies the protocol buffer language, both for ease of use and to make it available in a wider range of programming languages: our current release lets you generate protocol buffer code in Java, C++, Python, Java Lite, Ruby, JavaScript, Objective-C, and C#. In addition you can generate proto3 code for Go using the latest Go protoc plugin, available from the golang/protobuf Github repository. More languages are in the pipeline.

安装

在github上下载release版本link

protoc 是命令行工具

protobuf 是具体runtime

两个都要安装

项目的readme里面有具体安装方法

# linux x86_64
# -x socks... 是我自己的代理,可以不加
curl -x socks5://192.168.0.103:1080 -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.11.2/protobuf-all-3.11.2.zip
unzip protobuf-all-3.11.2.zip -d protobuf
cd protobuf/
cd protobuf-3.11.2/
./configure # 默认安装在 /usr/local
make
sudo make install
su root
echo "/usr/local/lib" >> /etc/ld.so.conf # 添加动态库的默认查找路径
ldconfig

在c++中使用

  1. .proto文件中定义消息格式
  2. 使用 protocol buffer 编译器编译生成代码
  3. 在c++中使用
  • 定义.proto文件
syntax = "proto2";

package tutorial; // 指定包名,防止命名冲突

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 phones = 4;
} message AddressBook {
repeated Person people = 1; // 重复的 理解为数组
}

每个元素上的“ = 1”,“ = 2”标记标识该字段在二进制编码中使用的唯一“标记”。 标签编号1至15与较高的编号相比,编码所需的字节减少了一个字节,因此,为了进行优化,您可以决定将这些标签用于常用或重复的元素,而将标签16和更高的标签用于较少使用的可选元素。 重复字段中的每个元素都需要重新编码标签号,因此重复字段是此优化的最佳候选者。

  • 编译 protocol buffer

    目的是生成读写 AddressBook (以及 Person 和 PhoneNumber)的类
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto

得到文件 addressbook.pb.h addressbook.pb.cc

  • 在代码中调用

    看起来是这样的:
#include <iostream>
#include <fstream>
#include <string>
#include "addressbook.pb.h"
using namespace std; tutorial::Person* person;
person->set_id(id);
getline(cin, *person->mutable_name());
person->set_email(email);
tutorial::Person::PhoneNumber* phone_number = person->add_phones();
phone_number->set_number(number);
phone_number->set_type(tutorial::Person::MOBILE); tutorial::AddressBook address_book;
address_book.ParseFromIstream(&input);
address_book.SerializeToOstream(&output); cout << "Person ID: " << person.id() << endl;
cout << " Name: " << person.name() << endl;
for (int j = 0; j < person.phones_size(); j++) {
const tutorial::Person::PhoneNumber& phone_number = person.phones(j);

具体代码见github

编译的时候请注意,系统可能存在老版本的libprotobuf.so文件,先用 locate libprotobuf.so 看一下,坑死我了

我安装的lib在/usr/local/lib下,而系统的在/usr/lib下,搜索优先级高,如果不卸载可以 -L/usr/local/lib -lprotobuf

不然可能报类似错误:对‘google::protobuf::MessageLite::ParseFromIstream(std::istream*)’未定义的引用

g++ -o test test_writing.cpp addressbook.pb.cc -lprotobuf

在go中使用

流程和c++一样

addressbook.proto文件:

syntax = "proto3";
package tutorial; import "google/protobuf/timestamp.proto"; 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;
}

编译,需要多安装一个为go生成代码的插件

export https_proxy=socks5://192.168.0.103:1080  # 这里我用了自己的代理,可以不加
go get github.com/golang/protobuf/protoc-gen-go

然后编译即可

protoc --go_out=. addressbook.proto

生成了addressbook.pb.go文件

go使用代码

package main

import (
"fmt"
proto "github.com/golang/protobuf/proto"
tutorial "github.com/zshorz/test_protobuf/test_go/tutorial"
"io/ioutil"
"log"
) func main() {
filename := "a.txt"
fmt.Println("will write in", filename) // write
person := tutorial.Person{
Name: "zsh",
Id: 1,
Email: "adgadg",
Phones: nil,
}
people := make([]*tutorial.Person,1)
people[0] = &person
book := &tutorial.AddressBook{}
book.People = people
// ... out, err := proto.Marshal(book); if err != nil {
log.Fatalln("Failed to encode address book:", err)
}
if err := ioutil.WriteFile(filename, out, 0644); err != nil {
log.Fatalln("Failed to write address book:", err)
} // read
in, err := ioutil.ReadFile(filename)
if err != nil {
log.Fatalln("Error reading file:", err)
}
book2 := &tutorial.AddressBook{}
if err := proto.Unmarshal(in, book2); err != nil {
log.Fatalln("Failed to parse address book:", err)
}
fmt.Println(book2)
} // out
// will write in a.txt
// people:<name:"zsh" id:1 email:"adgadg" >

具体代码见github

Protobuf用法的更多相关文章

  1. protobuf--数据序列化及反序列化

    ProtoBuf是一种灵活高效的独立于语言平台的结构化数据表示方法,可用于表示通信协议和数据存储等各方面,与XML相比,ProtoBuF更小更快更简单.你可以用定义自己ProtoBuf的数据结构,用P ...

  2. 解决protobuf不能直接在IOS上使用,利用protobuf-net在IOS上通讯

    ---------------------------------------------------------------------------------------------------- ...

  3. protobuf C++ 使用示例

    1.在.proto文件中定义消息格式 2.使用protobuf编译器 3.使用c++ api来读写消息 0.为何使用protobuf? 1.原始内存数据结构,可以以二进制方式sent/saved.这种 ...

  4. rpc框架: thrift/avro/protobuf 之maven插件生成java类

    thrift.avro.probobuf 这几个rpc框架的基本思想都差不多,先定义IDL文件,然后由各自的编译器(或maven插件)生成目标语言的源代码,但是,根据idl生成源代码这件事,如果每次都 ...

  5. google protobuf使用

    下载的是github上的:https://github.com/google/protobuf If you get the source from github, you need to gener ...

  6. protobuf c++ API

    1.在.proto文件中定义消息格式 2.使用protobuf编译器 3.使用c++ api来读写消息   0.为何使用protobuf?   1.原始内存数据结构,可以以二进制方式sent/save ...

  7. 使用CSharp编写Google Protobuf插件

    什么是 Google Protocol Buffer? Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,目前已经正在使用的有超过 ...

  8. SpringBoot整合Netty并使用Protobuf进行数据传输(附工程)

    前言 本篇文章主要介绍的是SpringBoot整合Netty以及使用Protobuf进行数据传输的相关内容.Protobuf会简单的介绍下用法,至于Netty在之前的文章中已经简单的介绍过了,这里就不 ...

  9. protobuf for java

    本文档为java编程人员使用protocol buffer提供了一个基本的介绍,通过一个简单的例程进行介绍.通过本文,你可以了解到如下信息: 1.在一个.proto文件中定义一个信息格式. 2.使用p ...

随机推荐

  1. zabbix3.4搭建钉钉报警

    1.在钉钉群里添加一个自定义的机器 在设置说明中无需开启Outgoing机制 红色箭头指的信息很重要后面脚本会用到 2.脚本 #!/usr/bin/python # -*- coding: utf-8 ...

  2. DISCUZ 如何为主题帖列表页添加头像,显示发帖者头像

    只显示名字的代码 ```php<em style=" font-size:14px;"> <!--{if $thread['authorid'] &&am ...

  3. HTML5的基础学习

    课前预习:HTML又被叫做超文本标记语言,它不是编程语言,是web中最微不足道的,但又是web中最微不足道的基石, 对零基础学习HTML的人员来说先认识HTML的标签和字体是必不可少的,万丈高楼平地起 ...

  4. python day02练习和作业

    # 1.请用代码实现:利用下划线将列表的每一个元素拼接成字符串,li=[‘alex’, ‘eric’, ‘rain’]# li=['alex','eric','rain']# print('_'.jo ...

  5. 懒人必备,IntelliJ IDEA中代码一键生成

    之前有不少小伙伴问松哥微人事项目(https://github.com/lenve/vhr)使用的 MyBatis 逆向工程在哪里?其实旧版微人事当时没有使用逆向工程,是我自己手动敲出来的,当然手动敲 ...

  6. shell命令之一天一见:awk

    AWK是一种优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一. 这种编程及数据操作语言(其名称得自于它的创始人阿尔佛雷德·艾侯.彼得·溫伯格和布萊恩·柯林漢姓氏的首个字 ...

  7. HDU_4496_逆向并查集

    http://acm.hdu.edu.cn/showproblem.php?pid=4496 逆向并查集,先读取,然后从后向前join每次保存答案即可. #include<iostream> ...

  8. CI框架扩展自定义控制器的方法

    扩展CI中的控制器 有时需要对CI中的控制器作统一操作,如进行登录和权限验证,这时就可以通过扩展CI控制器来实现. 扩展CI控制器只需要在application/core文件夹中建一个继承自CI_Co ...

  9. 为了控制Bean的加载我使出了这些杀手锏

    故事一: 绝代有佳人,幽居在空谷 美女同学小张,在工作中遇到了烦心事.心情那是破凉破凉的,无法言喻. 故事背景是最近由于需求变动,小张在项目中加入了MQ的集成,刚开始还没什么问题,后面慢慢问题的显露出 ...

  10. 【Java并发工具类】CountDownLatch和CyclicBarrier

    前言 下面介绍协调让多线程步调一致的两个工具类:CountDownLatch和CyclicBarrier. CountDownLatch和CyclicBarrier的用途介绍 CountDownLat ...