一种自动反射消息类型的 Google Protobuf 网络传输方案

本文探讨了在网络编程中使用Google Protobuf时遇到的长度和类型问题,并提出了利用protobuf反射功能根据type name自动创建Message对象的解决方案。作者通过DescriptorPool和MessageFactory,实现了无需手动注册消息类型即可自动创建和反序列化的功能,避免了switch-case或look-up table的传统做法。此外,文章介绍了自定义的protobuf传输格式,包含长度、类型信息和校验和,以确保数据完整性和可靠性。
摘要由CSDN通过智能技术生成

陈硕 (giantchen_AT_gmail)

Blog.csdn.net/Solstice  t.sina.com.cn/giantchen

 

这篇文章要解决的问题是:在接收到 protobuf 数据之后,如何自动创建具体的 Protobuf Message 对象,再做的反序列化。“自动”的意思是:当程序中新增一个 protobuf Message 类型时,这部分代码不需要修改,不需要自己去注册消息类型。其实,Google Protobuf 本身具有很强的反射(reflection)功能,可以根据 type name 创建具体类型的 Message 对象,我们直接利用即可。

本文假定读者了解 Google Protocol Buffers 是什么,这不是一篇 protobuf 入门教程。

本文以 C++ 语言举例,其他语言估计有类似的解法,欢迎补充。

本文的示例代码在: https://github.com/chenshuo/recipes/tree/master/protobuf

网络编程中使用 protobuf 的两个问题

Google Protocol Buffers (Protobuf) 是一款非常优秀的库,它定义了一种紧凑的可扩展二进制消息格式,特别适合网络数据传输。它为多种语言提供 binding,大大方便了分布式程序的开发,让系统不再局限于用某一种语言来编写。

在网络编程中使用 protobuf 需要解决两个问题:

  • 长度,protobuf 打包的数据没有自带长度信息或终结符,需要由应用程序自己在发生和接收的时候做正确的切分;
  • 类型,protobuf 打包的数据没有自带类型信息,需要由发送方把类型信息传给给接收方,接收方创建具体的 Protobuf Message 对象,再做的反序列化。

第一个很好解决,通常的做法是在每个消息前面加个固定长度的 length header,例如我在 《Muduo 网络编程示例之二: Boost.Asio 的聊天服务器》 中实现的 LengthHeaderCodec,代码见 http://code.google.com/p/muduo/source/browse/trunk/examples/asio/chat/codec.h

第二个问题其实也很好解决,Protobuf 对此有内建的支持。但是奇怪的是,从网上简单搜索的情况看,我发现了很多山寨的做法。

 

 

山寨做法

以下均为在 protobuf data 之前加上 header,header 中包含 int length 和类型信息。类型信息的山寨做法主要有两种:

  • 在 header 中放 int typeId,接收方用 switch-case 来选择对应的消息类型和处理函数;
  • 在 header 中放 string typeName,接收方用 look-up table 来选择对应的消息类型和处理函数。

这两种做法都有问题。

第一种做法要求保持 typeId 的唯一性,它和 protobuf message type 一一对应。如果 protobuf message 的使用范围不广,比如接收方和发送方都是自己维护的程序,那么 typeId 的唯一性不难保证,用版本管理工具即可。如果 protobuf message 的使用范围很大,比如全公司都在用,而且不同部门开发的分布式程序可能相互通信,那么就需要一个公司内部的全局机构来分配 typeId,每次增加新 message type 都要去注册一下,比较麻烦。

第二种做法稍好一点。typeName 的唯一性比较好办,因为可以加上 package name(也就是用 message 的 fully qualified type name),各个部门事先分好 namespace,不会冲突与重复。但是每次新增消息类型的时候都要去手工修改 look-up table 的初始化代码,比较麻烦。

其实,不需要自己重新发明轮子,protobuf 本身已经自带了解决方案。

 

根据 type name 反射自动创建 Message 对象

Google Protobuf 本身具有很强的反射(reflection)功能,可以根据 type name 创建具体类型的 Message 对象。但是奇怪的是,其官方教程里没有明确提及这个用法,我估计还有很多人不知道这个用法,所以觉得值得写这篇 blog 谈一谈。

 

以下是陈硕绘制的 Protobuf  class diagram,

评论 117
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值