文档章节

Protobuf简介

 张永昌
发布于 2015/08/26 16:54
字数 900
阅读 32
收藏 0

Protobuf 简介

Protobuf全称Google Protocol Buffers

  • 结构化数据存储格式(xml, json)

  • 用于通信协议、数据存储等

  • 高效的序列化和反序列化

  • 语言无关、平台无关、扩展性好

  • 官方支持C++, Java, Python三种语言

.proto文件

定义和使用

消息定义文件user_def.proto

package user;
message UserInfo { 
    required int64 id = 1;
    optional string name = 2;
    repeated bytes nick_name = 3;
}

编译.proto,生成解析器代码

protoc --cpp_out . user.proto  // user_def.pb.h user_def.pb.cc
protoc --java_out . user.proto // user/UserInfo.java

字段ID

optional string name = 2;

  • 唯一性

  • 序列化后,1~15占一个字节,16~2047占两个字节

字段类型

  • string vs. bytes

    .proto类型 c++类型 java类型 说明
    string std::string String 必须是UTF-8或ASCII文本
    bytes std::string ByteString 任意的字节序列

编写建议

  1. 常用消息字段(尤其是repeated字段)的ID尽量分配在1~15之间。

  2. 尽可能多的(全部)使用optional字段。

  3. 命名方式

    • .proto文件名用underscore_speparated_names。

    • 消息名用CamelCaseNames。

    • 字段名用underscore_separated_names。

兼容性建议

  1. 不能修改字段的ID。

  2. 不能增删任何required字段。

  3. https://developers.google.com/protocol-buffers/docs/proto#updating

序列化后的protobuf消息

  • 一序列的键值对,键是消息字段的ID。

  • 已知消息字段(.proto文件定义)按其ID顺序排列。

  • 未知消息字段:

    • c++和java: 排在已知字段之后且顺序不定。

    • python: 不保留未知字段。

  • 不包含未赋值的optional消息字段。

  • 使用little-endian字节序存储。

反射

反射是protobuf的一个重要特性,涉及到的类主要有:

根据名称创建消息

以下是一个根据消息名(包含package name)创建protobuf消息的C++函数,需要注意的是返回的消息必须在用完后delete掉。

Message* createMessage(const string &typeName) {
    Message *message = NULL;
    // 查找message的descriptor
    const Descriptor *descriptor = DescriptorPool::generated_pool()->FindMessageTypeByName(typeName);
    if (descriptor) {
        // 创建default message(prototype)
        const Message *prototype = MessageFactory::generated_factory()->GetPrototype(descriptor);
        if (NULL != prototype) {
            // 创建一个可修改的message
            message = prototype->New();
        }
    }
    return message;
}

修改消息

根据消息的字段名称修改其值。以上面的user.UserInfo为例,下面将一个新的UserInfo消息的其id字段设为100。

int main() {
    // 使用上面的函数创建一个新的UserInfo message
    Message *msg = createMessage("user.UserInfo");
    if (NULL == msg) {
        // 创建失败,可能是消息名错误,也可能是编译后message解析器
        // 没有链接到主程序中。
        return -1;
    }

    // 获取message的descriptor
    const Descriptor* descriptor = msg->GetDescriptor();
    // 获取message的反射接口,可用于获取和修改字段的值
    const Reflection* reflection = msg->GetReflection();

    // 根据字段名查找message的字段descriptor
    const FieldDescriptor* idField = descriptor->FindFieldByName("id");
    // 将id设置为100
    if (NULL != idField) {
        reflection->SetInt64(msg, idField, 100);
    }

    // ... 其他操作

    // 最后删除message
    delete msg;

    return 0;
}

从字符串或流中读取消息

createMessage创建一个空的消息后,最常见的使用场景是使用Message的ParseFromString或ParseFromIstream方法从字符串或流中读取一个序列化后的message。

    Message *msg = createMessage("user.UserInfo");
    if (NULL != msg) {
        if (!msg->ParseFromString("... serialized message string ... ")) {
            // 解析失败
            ...
        }
    }

Protobuf优势

  1. 扩展性好

    • 前后兼容

    • 引入(import)已定义的消息

    • 嵌套消息

  2. 高效

    • 适合处理大量小数据(单个Message不超过1M)

Protobuf劣势

  1. 没有内置的Set, Map等容器类型。

  2. 不适合处理单个Message超过1M的情景,详见Large Data Sets

进一步阅读

阅读资料


© 著作权归作者所有

共有 人打赏支持
粉丝 0
博文 1
码字总数 900
作品 0
武汉
Protobuffer | PHP安装Google protobuf及使用

PHP安装Google protobuf及使用 备注 项目采用redis集群(主从方式)存储数据;数据量月增50W,单个数据序列化情况下达到2k,继续压缩数据解决空间. 项目服务采用PHP(版本5.3)作为RPC服务版本. pro...

云迹
2017/02/05
0
0
Notepad++ 的 protobuf 高亮显示和列表显示

项目地址: https://github.com/chai2010/notepadplus-protobuf

chai2010
2015/07/29
0
0
Google Protobuf 开发指南

Google Protobuf开发指南 1.简介 l 它是开源项目:http://code.google.com/p/protobuf/ l 由google开发,并且在google内部使用 l Protobuf的作用和xml、json是一回事,但他是二进制格式,性能...

macwe
2013/08/29
0
1
Centos6.4下安装protobuf及简单使用

1、protobuf是google公司提出的数据存储格式,详细介绍可以参考:https://code.google.com/p/protobuf/ 2、下载最新的protobuf,下载地址:https://code.google.com/p/protobuf/downloads/li...

天下杰论
2015/05/09
0
0
我的Protobuf消息设计原则(续)--实践

1.首先为 聊天服务器(Chat)定义google protobuf的协议接口文件 接口主要遵循 Request、Response、Notification(Indication),Command(本文未出现)四大消息分类,并且使用Message顶层消...

newzai
2014/07/19
0
19

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JS:异步 - 面试惨案

为什么会写这篇文章,很明显不符合我的性格的东西,原因是前段时间参与了一个面试,对于很多程序员来说,面试时候多么的鸦雀无声,事后心里就有多么的千军万马。去掉最开始毕业干了一年的Jav...

xmqywx
今天
0
0
Win10 64位系统,PHP 扩展 curl插件

执行:1. 拷贝php安装目录下,libeay32.dll、ssleay32.dll 、 libssh2.dll 到 C:\windows\system32 目录。2. 拷贝php/ext目录下, php_curl.dll 到 C:\windows\system32 目录; 3. p...

放飞E梦想O
今天
0
0
谈谈神秘的ES6——(五)解构赋值【对象篇】

上一节课我们了解了有关数组的解构赋值相关内容,这节课,我们接着,来讲讲对象的解构赋值。 解构不仅可以用于数组,还可以用于对象。 let { foo, bar } = { foo: "aaa", bar: "bbb" };fo...

JandenMa
今天
1
0
OSChina 周一乱弹 —— 有人要给本汪介绍妹子啦

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @莱布妮子 :分享水木年华的单曲《中学时代》@小小编辑 手机党少年们想听歌,请使劲儿戳(这里) @须臾时光:夏天还在做最后的挣扎,但是晚上...

小小编辑
今天
21
5
centos7安装redis及开机启动

配置编译环境: sudo yum install gcc-c++ 下载源码: wget http://download.redis.io/releases/redis-3.2.8.tar.gz 解压源码: tar -zxvf redis-3.2.8.tar.gz 进入到解压目录: cd redis-3......

hotsmile
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部