protobuf入门

protobuf全称Protocol Buffers,是google推出的一种高效,快捷的数据交换格式,和XML,Thrift一样,都是一种数据交换协议(当然thrift还提供rpc的功能)。protobuf相对与xml结构化的文本数据格式,它是一种二进制的数据格式,具有更高的传输,打包和解包效率,这也是为什么protobuf很受欢迎的原因。

protobuf通过自己的编译器,对协议文件进行编译,生成对应语言的代码,方便的进行数据的打包和解包。目前,google 提供了三种语言的实现:javac++python,每一种实现都包含了相应语言的编译器以及库文件。

下面介绍protobuf的语法,protobuf的IDL都是保存为*.proto的文件中,proto文件中数据类型可以分为两大类:复合数据类型和标准数据类型。复合数据类型包括:枚举message类型标准数据类型包含:整型,浮点,字符串等,后面会详细介绍。

  • message

最常用的数据格式就是message,例如一个订单数据可以用message表示如下:

message Order
{
    required uint64 uid = 1;
    required float cost = 2;
    optional string tag = 3;
}

它经过protobuf编译成c++代码,会生成对应的XXX.pb.h和XXX.pb.cc。message会对应生成一个class,里面存放对应的data members,处理这些数据的函数,以及对应的打包和解包函数。

class Order : public ::google::protobuf::Message {
 public:
  ...
  // accessors -------------------------------------------------------
  ...

  ::google::protobuf::uint64 uid_;
  ::std::string* tag_;
  float cost_;
};

message数据格式中需要知道的:

1.每个字段末尾赋值的tag:该tag是用来标记该字段在序列化后的二进制数据中所在的field,每个字段的tag在message内部都是独一无二的。也不能进行改变,否则数据就不能正确的解包。

2.数据类型前面的修饰词:

  • required: 必须赋值,不能为空,否则该条message会被认为是“uninitialized”。build一个“uninitialized” message会抛出一个RuntimeException异常,解析一条“uninitialized” message会抛出一条IOException异常。除此之外,“required”字段跟“optional”字段并无差别。
  • optional:字段可以赋值,也可以不赋值。假如没有赋值的话,会被赋上默认值。
  • repeated: 该字段可以重复任意次数,包括0次。重复数据的顺序将会保存在protocol buffer中,将这个字段想象成一个可以自动设置size的数组就可以了。
  • 枚举

枚举和c++,java中的枚举类型是一个含义:

enum Corpus {
	UNIVERSAL = 0;
 	WEB = 1;
	IMAGES = 2;
	LOCAL = 3;
 	NEWS = 4;
 	PRODUCTS = 5;
	VIDEO = 6;
}

执行 protoc --cpp_out=.  enum_test.proto,会生成以下c++代码

enum Corpus {
  UNIVERSAL = 0,
  WEB = 1,
  IMAGES = 2,
  LOCAL = 3,
  NEWS = 4,
  PRODUCTS = 5,
  VIDEO = 6
};
  • 基本数据类型

protobuf支持的基本数据类型如下图:

  • message详解:

message数据格式在c++中被protobuf自动编译包含一下内容:

//xxx.proto
message Order
{
    required uint64 uid = 1;
    required float cost = 2;
    optional string tag = 3;
}

//xxx.pb.h
<pre name="code" class="cpp">class Order : public ::google::protobuf::Message {
 public:
  ...
  // accessors -------------------------------------------------------

  // required uint64 uid = 1;
  inline bool has_uid() const;
  inline void clear_uid();
  static const int kUidFieldNumber = 1;
  inline ::google::protobuf::uint64 uid() const;
  inline void set_uid(::google::protobuf::uint64 value);

  // required float cost = 2;
  inline bool has_cost() const;
  inline void clear_cost();
  static const int kCostFieldNumber = 2;
  inline float cost() const;
  inline void set_cost(float value);

  // optional string tag = 3;
  inline bool has_tag() const;
  inline void clear_tag();
  static const int kTagFieldNumber = 3;
  inline const ::std::string& tag() const;
  inline void set_tag(const ::std::string& value);
  inline void set_tag(const char* value);
  inline void set_tag(const char* value, size_t size);
  inline ::std::string* mutable_tag();
  inline ::std::string* release_tag();
  inline void set_allocated_tag(::std::string* tag);

  // @@protoc_insertion_point(class_scope:Order)
 private:
  inline void set_has_uid();
  inline void clear_has_uid();
  inline void set_has_cost();
  inline void clear_has_cost();
  inline void set_has_tag();
  inline void clear_has_tag();

  ::google::protobuf::uint32 _has_bits_[1];

  ::google::protobuf::uint64 uid_;
  ::std::string* tag_;
  float cost_;
};

对于每一个message的data member,protobuf会自动生成相关的处理函数,对于每一个字段主要的处理函数有:has_uid(), clear_uid(), uid(), set_uid(),它们分别用于判断该字段是否被设置,清除该字段设置记录,获得该字段,设置该字段。对于示例中的uid字段,对应函数的实现如下:

//xxx.pb.h

// required uint64 uid = 1;
inline bool Order::has_uid() const {
  return (_has_bits_[0] & 0x00000001u) != 0;
}
inline void Order::set_has_uid() {
  _has_bits_[0] |= 0x00000001u;
}
inline void Order::clear_has_uid() {
  _has_bits_[0] &= ~0x00000001u;
}
inline void Order::clear_uid() {
  uid_ = GOOGLE_ULONGLONG(0);
  clear_has_uid();
}
inline ::google::protobuf::uint64 Order::uid() const {
  // @@protoc_insertion_point(field_get:Order.uid)
  return uid_;
}
inline void Order::set_uid(::google::protobuf::uint64 value) {
  set_has_uid();
  uid_ = value;
  // @@protoc_insertion_point(field_set:Order.uid)
}

由实现代码可知,代码是通过_has_bits_来标记字段是否已经被设置,_has_bits_的定义如下:

::google::protobuf::uint32 _has_bits_[1];

通过_has_bits_的位来表达各个字段是否被设置。分别通过0x01, 0x02, 0x04...来分别标记第1,2,3,,,各个field是否已经被设置。

对于protobuf将协议数据序列化为二进制数据的接口有如下:

// Serialization ---------------------------------------------------
  // Methods for serializing in protocol buffer format.  Most of these
  // are just simple wrappers around ByteSize() and SerializeWithCachedSizes().

  // Write a protocol buffer of this message to the given output.  Returns
  // false on a write error.  If the message is missing required fields,
  // this may GOOGLE_CHECK-fail.
  bool SerializeToCodedStream(io::CodedOutputStream* output) const;
  // Like SerializeToCodedStream(), but allows missing required fields.
  bool SerializePartialToCodedStream(io::CodedOutputStream* output) const;

  // Write the message to the given zero-copy output stream.  All required
  // fields must be set.
  bool SerializeToZeroCopyStream(io::ZeroCopyOutputStream* output) const;
  bool SerializePartialToZeroCopyStream(io::ZeroCopyOutputStream* output) const;

  // Serialize the message and store it in the given string.  All required
  // fields must be set.
  bool SerializeToString(string* output) const;
  bool SerializePartialToString(string* output) const;

  // Serialize the message and store it in the given byte array.  All required
  // fields must be set.
  bool SerializeToArray(void* data, int size) const;
  bool SerializePartialToArray(void* data, int size) const;

  string SerializeAsString() const;
  string SerializePartialAsString() const;

  // Like SerializeToString(), but appends to the data to the string's existing
  // contents.  All required fields must be set.
  bool AppendToString(string* output) const;
  bool AppendPartialToString(string* output) const;

  // Serialize the message and write it to the given file descriptor.  All
  // required fields must be set.
  bool SerializeToFileDescriptor(int file_descriptor) const;
  bool SerializePartialToFileDescriptor(int file_descriptor) const;

  // Serialize the message and write it to the given C++ ostream.  All
  // required fields must be set.
  bool SerializeToOstream(ostream* output) const;
  bool SerializePartialToOstream(ostream* output) const;
时间: 2025-01-04 18:47:27

protobuf入门的相关文章

Windows环境下google protobuf入门

我使用的是最新版本的protobuf(protobuf-2.6.1),编程工具使用VS2010.简单介绍下google protobuf: google protobuf 主要用于通讯,是google出的一个结构化信息传递工具,有着效率高.占存储少的优点,常被用于网络通讯. Google protobuf主要是针对Linux下的开发,但是为了照顾windows的开发人员,google也给出了相应的方案. windows下,需要下载两个包protobuf-2.6.1.tar.bz2和protobu

C# ProtoBuf 入门

个人理解:protobuf 就是一种传输数据的协议,或者说格式,跟json类似. 首先罗列下需要的工具: VS2015 protobuf-csharp-port-master 下载地址:https://github.com/jskeet/protobuf-csharp-port(备注:有另一种工具protobuf-net使用起来更方便,有兴趣的可以参考这篇文章:http://www.cnblogs.com/jhli/p/6139914.html) 首先,将下载好的 protobuf-csharp

Google Protobuf 使用 Java 版

一 . Protobuf 的入门 Protobuf 是一个灵活,高效,结构化的数据序列化框架, 相比于 XML 等传统的序列化工具,它更小,更快,更灵活,更简单. Protobuf 支持数据结构化一次可以到处使用.甚至跨语言使用.同通过代码生成工具可以自动生成不同语言版本的源代码,甚至可以在使用不同版本的数据结构中进行数据传递,实现数据结构的向前兼容. Google 的 protobuf 在业界非常流行,很多商业项目选择 protobuf 作为编码解码框架,这里我们一起回顾一下 Protobuf

Google Protobuf在Netty中的使用

[toc] Google Protobuf在Netty中的使用 程序代码来自于<Netty权威指南>第8章,已经加了注释,不过需要注意的是,使用的proto源代码是在Google Protobuf入门与使用中生成的,关于protobuf代码自动生成工具的使用可以参考这篇文章. 例子中,通过解码器ProtobufVarint32FrameDecoder和编码器ProtobufVarint32LengthFieldPrepender的使用已经解决了半包问题,测试时可以把其注释掉,这样就可以演示Ne

protobuf c++入门

1.在.proto文件中定义消息格式 2.使用protobuf编译器 3.使用c++ api来读写消息 0.为何使用protobuf? 1.原始内存数据结构,可以以二进制方式sent/saved.这种方式需要相同的内存布局和字节序. 2.以ad-hoc方式将数据项编码成一个简单字符串----比如,将4个int类型编码成"12:3:-23:67".这种方式简灵活.适用于简单数据. 3.将数据序列化为XML.这种方式很流行,因为xml可读性好,编码解码方便,性能也好.仅仅XML dom树比

protobuf 简单入门

1. 概述 protobuf(Protocol Buffers )是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化.它很适合做数据存储或 RPC 数据交换格式.可用于通讯协议.数据存储等领域的语言无关.平台无关.可扩展的序列化结构数据格式.目前提供了 C++.Java.Python 三种语言的 API. 特点: 结构数据串行化,灵活.高效.自动. 相对XML,更小.更快.更简单. 自定义数据结构. 动态更新数据结构. 2. 安装protobuf 首先,可以从github

Protobuf 从入门到实战

简介 从第一次接触Protobuf到实际使用已经有半年多,刚开始可能被它的名字所唬住,其实就它是一种轻便高效的数据格式,平台无关.语言无关.可扩展,可用于通讯协议和数据存储等领域. 优点 平台无关,语言无关,可扩展: 提供了友好的动态库,使用简单: 解析速度快,比对应的XML快约20-100倍: 序列化数据非常简洁.紧凑,与XML相比,其序列化之后的数据量约为1/3到1/10. 使用详解 1.服务器安装 安装依赖的库:     autoconf automake libtool curl mak

一个入门rpc框架的学习

一个入门rpc框架的学习 参考 huangyong-rpc 轻量级分布式RPC框架 该程序是一个短连接的rpc实现 简介 RPC,即 Remote Procedure Call(远程过程调用),说得通俗一点就是:调用远程计算机上的服务,就像调用本地服务一样. RPC 可基于 HTTP 或 TCP 协议,Web Service 就是基于 HTTP 协议的 RPC, 它具有良好的跨平台性,但其性能却不如基于 TCP 协议的 RPC.会两方面会直接影响 RPC 的性能,一是传输方式,二是序列化. 众所

android入门开发教程之网络性能的优化

我在麦子学院上android开发的时候,麦子学院android开发老师讲到Android开发过程中经常会涉及到性能优化的问题,应该从基础.网络.测试等各个层面进行整合优化.现在咱们聊聊Android开发之网络性能的优化. 1)避免频繁网络请求 访问server端时,建立连接本身比传输需要跟多的时间,如非必要,不要将一交互可以做的事情分成多次交互(这需要与Server端协调好).有效管理Service 后台服务就相当于一个持续运行的Acitivity,如果开发的程序后台都会一个service不停的