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

陈硕 (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,

  • 11
    点赞
  • 147
    收藏
    觉得还不错? 一键收藏
  • 117
    评论
protobufProtocol Buffers)是一种轻量级的数据序列化格式,用于网络传输和存储数据。它提供了一种简单而高效的方法来将结构化数据编码为二进制格式,并在不同平台之间进行传输和解析。 在网络传输中使用protobuf,首先需要定义数据的结构和字段类型。这可以通过编写一个.proto文件来完成,其中定义了消息的字段和类型。然后,使用protobuf编译器将.proto文件编译成适合所使用语言的代码。 在发送端,将要发送的数据按照protobuf定义的结构进行编码,并将其作为二进制数据发送给接收端。接收端收到数据后,可以使用相同的protobuf定义结构进行解码,并还原为原始数据。 protobuf具有以下优点: 1. 高效性:protobuf使用二进制编码,相比于文本格式(如XML、JSON),它的编码和解码速度更快,占用更小的网络带宽。 2. 可扩展性:protobuf支持向已定义消息中添加新字段,而不会破坏已有代码的兼容性。这使得系统能够逐步演化而不需要对所有组件进行修改。 3. 跨平台支持:由于protobuf一种语言无关的格式,可用于多种编程语言,如C++、Java、Python等。 4. 易于使用:protobuf提供了简单易用的API,使得编码和解码数据变得简单。 需要注意的是,虽然protobuf网络传输方面具有优势,但也需要进行版本管理,以确保发送端和接收端使用的是相同的.proto文件和相同版本的protobuf库。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 117
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值