google protobuf学习笔记一:使用和原理

一.什么是protobuf

protobuf全称Google Protocol Buffers,是google开发的的一套用于数据存储,网络通信时用于协议编解码的工具库。它和XML或者JSON差不多,也就是把某种数据结构的信息,以某种格式(XML,JSON)保存起来,protobuf与XML和JSON不同在于,protobuf是基于二进制的。主要用于数据存储、传输协议格式等场合。那既然有了XML等工具,为什么还要开发protobuf呢?主要是因为性能,包括时间开销和空间开销:

1.时间开销:XML格式化(序列化)和XML解析(反序列化)的时间开销是很大的,在很多时间性能上要求很高的场合,你能做的就是看着XML干瞪眼了。

2.空间开销:熟悉XML语法的同学应该知道,XML格式为了有较好的可读性,引入了一些冗余的文本信息。所以空间开销也不是太好(应该说是很差,通常需要实际内容好几倍的空间)。

据实验(当然不是我实验),一条消息数据,用protobuf序列化后的大小是json格式的十分之一,xml格式的二十分之一。

这一篇主要讲protobuf用作数据存储方面,下一篇讲用作rpc通讯协议方面。

二.使用protobuf

注:我只会讲语言特性,至于环境配置之类的,请大家自行Google。

protobuf的使用很简单,开发人员按照一定的语法定义结构化的消息格式,然后用自带的变异工具,工具将自动生成相关的类,官方支持java、c++、python语言环境(当然可以在网上找到很多支持其他语言的封装,当然你也可以自己写一个,只要符合google定义的格式)。通过将这些类包含在项目中,可以很轻松的调用相关方法来完成业务消息的序列化与反序列化工作。

1.定义报文格式。protobuf文件的后缀是proto,是一种类似c++或者java的语法。使用protoc.exe(windows平台下,你可以下载源码编译,也可以网上直接下载exe,这个大家自行Google)把proto文件编译成c++,java或者Python就可以使用了。

package my;
message Person
{
	required string name = 1;
	optional int32  age  = 2;
}; 

在这里定义了一个Person,我们只是简单的定义了name和age。这里注意,在上例中,package 名字叫做 my,定义了一个消息 Person,该消息有2个成员,类型为 string 的 name,另一个为类型为 int32 的成员 age。optional 代表这是一个可选的成员,即消息中可以不包含该成员,required代表是必须的。

写好proto之后把proto放在protoc.exe相同目录,然后在此目录使用指令:protoc --cpp_out=d:\proto person.proto(我们使用的是c++)。当用protocolbuffer编译器来运行.proto文件时,编译器将生成所选择语言的代码,这些代码可以操作在.proto文件中定义的消息类型,包括获取、设置字段值,将消息序列化到一个输出流中,以及从一个输入流中解析消息。

就可以生成person.pb.h,person.pb.cc.在生成的头文件中,定义了一个
C++ 类 Person,继承自google::protobuf::Message,后面我们进行对Person数据的文件读写, 将使用这个类来对消息进行操作。诸如对消息的成员进行赋值,将消息序列化等等都有相应的方法。

首先,把数据写入disk:

#include "person.pb.h"
…
int main(void)
{
	Person person;
	person.set_name("flamingo");
	person.set_age(18); 

	// Write
	fstream output("./log", ios::out | ios::trunc | ios::binary); 

	if (!person.SerializeToOstream(&output)) {
		cerr << "Failed to write msg." << endl;
		return -1;
	}
	return 0;
}

先定义一个Person,然后给Person赋值,其中set_name,set_age是根据proto自动生成的,我们使用SerializeToOstream
将对象序列化成二进制(导致了可读性差的问题,这算是protobuf的一个缺点吧)后写入一个 fstream 流。

然后在从disk读出Person的数据:

#include "person.pb.h"
…
void PrintInfo(const Person & person) {
	cout << person.name() << endl;
	cout << person.age() << endl;
} 

int main(int argc, char* argv[]) {
	Person person;
	{
		fstream input("./log", ios::in | ios::binary);
		if (!person.ParseFromIstream(&input)) {
			cerr << "Failed to parse address book." << endl;
			return -1;
		}
	} 

	PrintInfo(person);
…
}

主要是利用 ParseFromIstream 从一个 fstream 流中读取序列化的信息并反序列化。

下一篇将讲利用protobuf rpc进行数据传输。

时间: 2024-10-05 16:32:57

google protobuf学习笔记一:使用和原理的相关文章

google protobuf学习笔记一:windows下环境配置

欢迎转载,转载请注明原文地址:http://blog.csdn.net/majianfei1023/article/details/45371743 protobuf的使用和原理,请查看:http://blog.csdn.net/majianfei1023/article/details/45112415 Windows下google protobuf开发环境配置 最近项目需求,Client与Server的网络通信协议传输使用google protobuf rpc.对于Protobuf,以前是只

Java IO学习笔记:概念与原理

Java IO学习笔记:概念与原理 一.概念 Java中对文件的操作是以流的方式进行的.流是Java内存中的一组有序数据序列.Java将数据从源(文件.内存.键盘.网络)读入到内存 中,形成了流,然后将这些流还可以写到另外的目的地(文件.内存.控制台.网络),之所以称为流,是因为这个数据序列在不同时刻所操作的是源的不同部分. 二.分类 流的分类,Java的流分类比较丰富,刚接触的人看了后会感觉很晕.流分类的方式很多: 1.按照输入的方向分,输入流和输出流,输入输出的参照对象是Java程序. 2.

C++学习笔记34 模版的原理

模版在C++中具有非常重要的地位,STL就是大量运用模版写出来的. 模版的优点我就不一一列举了.这里我只说一下模版的原理. 当编译器遇到模版方法定义的时候,编译器进行语法检查,但是并不会编译模版.编译器无法编译模版定义,因为编译器不知道要使用的类型是什么,编译器不知道x和y的类型的情况下无法为x=y这样的语句生成代码. 当编译器遇到一个实例化的模版的时候,例如vector<int> vi(这里我只是拿vector举例,实际上基本类型的vector代码好像会自动存在编译器中),编译器会将模版类定

protobuf 学习笔记

它是什么 术语定义 protocol buffer 官网github定义:https://github.com/google/protobuf https://developers.google.com/protocol-buffers/  开发者帮助 百度百科定义:http://baike.baidu.com/link?url=vlbJtV9p9Vfj4wQDif_XaNymBZI67u3AFjF5ZpT6iJjOwGfsenwUZMieBGrtlUC0FkWwWQic-Y3rwXYP0tq9

HCNP学习笔记之OSPF协议原理及配置9-基础知识特殊区域

为了减少外部路由对内部路由器的影响,可以通过设置特殊区域减少路由的数量. 因为对于内部路由不需要知道外部路由的明细. 即特殊区域是为了减少LSDB的规模. 1 stub区域,过滤了4类,5类 LSA,以一条到外部网络的默认路由替代. stub 区域实例: 由路由表可以看出,区域间路由(3类 network-summary-LSA)可以通告到stub中. 5类as-external-LSA被过滤,外部路由被转换成一条默认路由. 2 完全stub区域,过滤了3,4,5类LSA,拓扑和上例相同. 3

HCNP学习笔记之OSPF协议原理及配置1-基础知识

7.25日在济南博赛参加了HCNP的培训,感觉和HCDA不同,内容偏重理论,多而杂,现整理一下,和大家分享,也希望得到高手的指点. 先说下学习的感想和给初学者的建议: 学习的过程本身对自己就一种锻炼,要做好吃苦的准备,坚持下去,你一定会取得不凡的成就. 理论学习和操作是个迭代的过程. 很多同学花时间去背命令,我觉的不是可取的.命令只是一个工具,可以通过练习强化.但我们除了要知道怎么作(操作),还要知道为什么要这么做(理论).这样很好的解决实际当中遇到的问题. 所以,学习应该是理论-实践-理论-实

Android(java)学习笔记95:Android原理揭秘系列之View、ViewGroup

作过Android 应用开发的朋友都知道,Android的UI界面都是由View和ViewGroup及其派生类组合而成的.其中,View是所有UI组件的基类,而ViewGroup是容纳这些组件的容器,其本身也是从View派生出来的.AndroidUI界面的一般结构可参见下面的示意图: 可见,作为容器的ViewGroup可以包含作为叶子节点的View,也可以包含作为更低层次的子ViewGroup,而子ViewGroup又可以包含下一层的叶子节点的View和ViewGroup.事实上,这种灵活的Vi

【知了堂学习笔记】ajax工作原理

ajax工作原理 什么是ajax? ajax 的全称是Asynchronous JavaScript and XML,其中,Asynchronous 是异步的意思.从全称中就可以看出AJAX = 异步 JavaScript 和 XML.  AJAX 是一种用于创建快速动态网页的技术.通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新.这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新.传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面. 使用 AJ

Android学习笔记View的工作原理

自定义View,也可以称为自定义控件,通过自定义View可以使得控件实现各种定制的效果. 实现自定义View,需要掌握View的底层工作原理,比如View的测量过程.布局流程以及绘制流程,除此之外,还需要掌握View常见的回调方法.而对于那些具有滑动效果的自定义View,我们还需要处理View的滑动,如果遇到滑动冲突则需要处理相应的滑动冲突. 下面是View的常见回调方法: 构造方法 onAttach onVisibilityChanged onDetach onFinishInflate on