前言

google开源的Protocol Buffers(后面简称protobuf)作为一种结构化数据序列化和反序列化的工具,在很多场景中都有应用,而extend的拓展机制又增加了很多可能性。下面通过一个示例来简单说明一下如何使用protobuf拓展和编写插件。

问题

游戏服务器开发的时候,会把数据放入protobuf结构中进行序列化,然后放入key-value db中,从db加载出来后再反序列化成一个protobuf对象,有时候我们可能不能直接使用protobuf对象,而是需要转换成一个C struct(如需要放入共享内存的时候)。这时候我们就需要一种很方便把protobuf定义的message可以映射成一个C结构,同时又能从一个C结构还原成protobuf的message的方式。每次都逐个字段的去写,即繁琐又容易出错,一般这种能让工具生成是最好的。

protobuf拓展

我们需要指定哪些message需要生成c struct,哪些不需要,因此我们可以定义message的拓展。 新建一个文件,假设叫做 pod_options.proto

import "google/protobuf/descriptor.proto";extend google.protobuf.MessageOptions{ // 1: need to generate pod data code // 2: need to generate pod data code without constructor optional int32 gen_pod = 30000;}

接下来,可以定义我们自己的test.proto了。

import "pod_options.proto";message NeedPod{ // 设置了1,需要生成 c struct option (gen_pod) = 1; optional uint32 id = 1;}message DontNeedPod{ optional uint32 id = 1;}

解析proto文件

有了拓展字段,接下来怎么获取呢,难道要修改protoc的源码,输出需要的c struct么? 其实,并不需要修改源码,起码有几种方法可以达到目的。

使用Importer

仔细阅读protoc源码,有一个 google::protobuf::compiler::Importer 类

// Simple interface for parsing .proto files. This wraps the process// of opening the file, parsing it with a Parser, recursively parsing all its// imports, and then cross-linking the results to produce a FileDescriptor. This is really just a thin wrapper around SourceTreeDescriptorDatabase.// You may find that SourceTreeDescriptorDatabase is more flexible. TODO(kenton): I feel like this class is not well-named.class PROTOBUF_EXPORT Importer {

public:

Importer(SourceTree* source_tree, MultiFileErrorCollector* error_collector);

// Import the given file and build a FileDescriptor representing it. If // the file is already in the DescriptorPool, the existing FileDescriptor // will be returned. The FileDescriptor is property of the DescriptorPool, // and will remain valid until it is destroyed. If any errors occur, they // will be reported using the error collector and Import() will return NULL. // // A particular Importer object will only report errors for a particular // file once. All future attempts to import the same file will return NULL // without reporting any errors. The idea is that you might want to import // a lot of files without seeing the same errors over and over again. If // you want to see errors for the same files repeatedly, you can use a // separate Importer object to import each one (but use the same // DescriptorPool so that they can be cross-linked). const FileDescriptor* Import(const std::string& filename);

//………………}

早期的protobuf版本就是用这个类来产生FileDescriptor,而有了FileDescriptor,就有了整个proto文件的所有信息。Importer的用法可以参照早期版本的protoc源码,或者在单元测试用例中也仍然有用到Importer,大概代码如下:

MultiFileErrorCollector error_collector;

DiskSourceTree source_tree;

// MapPath的用法可以查看源码的注释,这里就不细说了source_tree.MapPath("", "./");

Importer importer(&source_tree, &error_collector);

const FileDescriptor* parsed_descriptor = importer.Import("test.proto");

使用py2文件

还有一种方法可以以曲线救国的方式来实现我们的目的。我们知道protoc可以支持产出不同语言的目标文件,而针对python的目标文件就是py2.py文件,查看 py2 文件,可以看到,里面已经包含了FileDescriptor类了,因此,只要用python写一个脚本加载这个py2文件,就可以获得一个FileDescriptor类

protobuf插件

相比于前面的两种方法,protobuf官方支持自定义插件,只要根据protobuf要求的方式编写插件,大概的格式如下:

#include #include #include #include #include using namespace google::protobuf::compiler;

class PodCodeGenerator : public CodeGenerator

{

public:

virtual ~PodCodeGenerator(){};

virtual bool Generate(const ::google::protobuf::FileDescriptor* file_, const string& parameter, GeneratorContext* context, string* error) const

{

// 根据FileDescriptor,产生输出文件的信息 return true;

}

};

int main(int argc, char* argv[])

{

PodCodeGenerator generator;

return google::protobuf::compiler::PluginMain(argc, argv, &generator);

}

可以看到,Generate函数的参数里面已经有protobuf解析好的FileDescriptor了,接下来就是根据自己需要的格式生成了。至于调用插件的方式也是很简单,假设插件的二进制文件叫test_plugin,则如下:protoc --proto_path=your path --NAME_out=output path --plugin=protoc-gen-NAME=test_plugin test.proto

其中的NAME可以是自定义的字符串,另外还可以加上 -NAME_opt=your param 选项带上参数给插件。使用插件的方式可以很好的在单次解析中完成pb和自定义格式的输出。

P.S. 插件的示例源码

java protobuf extend_如何使用protobuf extend和编写protobuf插件相关推荐

  1. 解决:Exception in thread “main“ java.io.IOException: Failed on local exception: com.google.protobuf

    集群上提交运行jar包程序,出现如下错误: Exception in thread "main" java.io.IOException: Failed on local exce ...

  2. 解决java.io.IOException: Failed on local exception: com.google.protobuf.InvalidProtocolBufferException

    解决 java.io.IOException: Failed on local exception: com.google.protobuf.InvalidProtocolBufferExceptio ...

  3. java记事本应用程序_Java教程:使用记事本编写运行Java程序

    Java教程经过上节的操作已经配置完了 Java 的开发环境,但并不清楚所配置的开发环境是否真的可以运行 Java 应用程序.为了解除这个疑虑,也为了使读者对开发 Java 应用程序的步骤有一个初步的 ...

  4. 基于java 工单管理_实训任务工单1-2(编写规范Java代码) 实训任务工单1-2(编写规范Java代码).docx_学小易找答案...

    [其它]实训任务工单4-1(泛型类.泛型方法的应用) 实训任务工单4-1(泛型类.泛型方法的应用).docx [简答题]教学工单5-1Java序列化机制的使用 [填空题]The name of my ...

  5. 曾经的 Java IDE 王者 Eclipse 真的没落了?21 款插件让它强大起来!

    俗话说,好马配好鞍,才能展现千里马的实力.一名好的开发者,必定要有一套好的开发工具才能打造出最好的产品给用户.要论世界上最好用的 IDE 是哪一种?有人会选择老牌的 Visual Studio 或是 ...

  6. java应用程序如何编译运作_开发Java应用程序的基本步骤是: 1 编写源文件, 2.编译源文件, 3.运行程序。_学小易找答案...

    [判断题]Java源文件中只能有一个类. [简答题]任务32:开关电源PCB 设计.docx [多选题]企业的收入具体表现为一定期间: [简答题]任务33:CPLD逻辑电路自制元件与封装.docx [ ...

  7. Java实现聊天软件(一)界面编写

    文章目录 Java实现聊天软件(一)界面编写 介绍 IM(Instant Messenger)工作原理 登录界面 界面设计 代码实现 导包 继承建类 定义组件 构造函数 成品展示 好友栏界面 例子展示 ...

  8. 计网实验一 假设Tom和Jerry利用Java UDP进行聊天,请为他们编写程序。具体如下:

    一[实验目的] 掌握基于多线程的复杂网络程序的开发方法和开发流程: 按照要求设计实现软件,以培养应用复杂计算系统开发的能力,并在设计和开发过程中体现出创新意识. 二[实验要求] 以下每个实验均要求: ...

  9. 假设Tom和Jerry利用Java UDP进行聊天,请为他们编写程序。

    假设Tom和Jerry利用Java UDP进行聊天,请为他们编写程序.具体如下: (1).Tom和Jerry聊天的双方都应该具有发送端和接收端: (2).利用DatagramSocket与Datagr ...

最新文章

  1. Visual Studio 2017软件安装教程
  2. 基于R语言的梯度推进算法介绍
  3. jqueryppt_jquery简单实现幻灯片的方法
  4. Android 7.0 Gallery图库源码分析2 - 分析启动流程
  5. javascript练习----复选框全选,全不选,反选
  6. eclipse反编译插件Jadclipse介绍
  7. centos安装软件【google浏览器,QQ】【拷贝旧的文件源作为备份】【软件源更换为清华源】
  8. information_schema.engines学习
  9. 箭头函数写法_箭头函数
  10. laravel的表单验证(下面有些信息未验证,转的)
  11. 服务式GIS实践与发展——REST 服务
  12. 【C语言】流程图符号及流程图
  13. meson test 的 --test-args 参数
  14. 装完linux无法进入windows,安装Ubuntu后无法启动Windows,如何解决?
  15. 推荐一款非常好看notepad++主题和字体
  16. 静态单赋值(二)—gcc中的SSA化算法
  17. android 版本更新原理,蒲公英 - 文档中心 - SDK 自动更新机制
  18. [转载]livid 写给他自己的
  19. 循环控制语句break,continue
  20. 如何初版一本书——出版社选择

热门文章

  1. Angel深度学习在广告推荐训练优化中的实践.pdf(附下载链接)​
  2. leetcode力扣64. 最小路径和
  3. MoSE: 多任务混合序列专家模型
  4. 文件可以直接删除吗_原来手机中的这些文件可以删除,难怪手机越用越卡
  5. 5h是什么意思_2B铅笔中的2B是啥意思?
  6. Leetcode每日一题:724.Find Pivot Index(寻找中心索引)
  7. OPPO大数据平台运营研发实践分享
  8. iOS Coding Style Guide 代码规范
  9. 第十六:Allure-pytest功能特性介绍
  10. 第二:HttpClient+testNG实现对接口的测试及校验(接口自动化落地)