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

这篇文章要解决的问题是:在接收到 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。

时间: 2024-09-19 09:21:08

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

4G牌照正式发放的消息一出,惊人的网络传输速度让人们津津乐道

而以无线通信技术为载体的智能家居产业也以"首席受益者"的身份进入人们的视线.事实上,智能家居并非是一个新兴的概念,其已悄然发展了近十年.但由于技术方面的不够成熟,在相当长的一段时间内,智能家居都与消费者无形间拉开了一定的距离.近些年,随着智能家居市场推广普及的进一步落实,为了争夺巨大的市场蛋糕,一大批智能家居品牌开始崛起,将智能家居这种新的生活方式推向消费者.而与其他行业相一致,智能产业在发展过程中难免会出现"鱼龙混杂"."名不副实"的情况.经过

微信公众平台开发入门教程(三)消息类型讲解

接收消息类型 目前普通用户能向公众账号推送五种格式的消息:文本(包括表情).语音.图片.视频.位置.链接.名片发送会失败.下面就这五种分别详解如下: 1. 文本(包括表情)发送文本 后台格式: <xml> <ToUserName><![CDATA[gh_680bdefc8c5d]]></ToUserName> <FromUserName><![CDATA[oIDrpjqASyTPnxRmpS9O_ruZGsfk]]></From

PHP-微信公众平台开发-接收用户输入消息类型并响应

原文:PHP-微信公众平台开发-接收用户输入消息类型并响应 <?php // 该代码块用于接收用户消息,根据用户输入的消息类型进行判断,文本,图片,视频,位置,链接,语音等,并取得值,处理后给予响应. // 接收用户消息 // 微信公众账号接收到用户的消息类型判断 // define("TOKEN", "weixin"); $wechatObj = new wechatCallbackapiTest(); if (!isset($_GET['echostr']

byte-关于自动提升int类型疑问?

问题描述 关于自动提升int类型疑问? byte b1= 1; byte b2 =2; byte b3 =b1+b2; 这种编译为什么会报错,求指导? 解决方案 当使用+.-.*./.%运算符对基本类型进行运算时,遵循如下规则: 只要两个操作数中有一个是double类型的,另一个将会被转换成double类型,并且结果也是double类型: 否则,只要两个操作数中有一个是float类型的,另一个将会被转换成float类型,并且结果也是float类型: 否则,只要两个操作数中有一个是long类型的,

visual studio 2013-visual studio的事件处理程序向导中消息类型为空

问题描述 visual studio的事件处理程序向导中消息类型为空 我创建了一个简单的win32项目,然后添加了一个菜单资源,添加了几个菜单项. 然后我右键使用"事件处理程序向导",它的"消息类型"框中是空的,正常的应该有一些消息类型的.如图:

mysql把主键定义为自动增长标识符类型_Mysql

1.把主键定义为自动增长标识符类型 在mysql中,如果把表的主键设为auto_increment类型,数据库就会自动为主键赋值.例如: create table customers(id int auto_increment primary key notnull, name varchar(15)); insert into customers(name) values("name1"),("name2"); 一旦把id设为auto_increment类型,my

大数据-怎么统一关系型数据库,非关系型数据库,文件类型以及消息类型(如网页)的接口

问题描述 怎么统一关系型数据库,非关系型数据库,文件类型以及消息类型(如网页)的接口 最近接了个需求,就是要统一如题的各种接口,小弟从来没做过类似的东西.希望各位能给点例子. 解决方案 可以考虑工厂模式和适配器模式

SDK自动存储消息问题

问题描述 是不是只有两个人同时在线时的对话SDK才会自动存储消息,当我一个人在的时候发的消息是属于离线消息是吗,SDK在接收方还没有收到离线消息是不是不会自动存储消息 解决方案 无论是在线消息,还是离线消息SDK都会将消息自动保存在本地数据库,具体的你可以到我们demo中- (void)didReceiveOfflineMessages:(NSArray *)offlineMessages 这个接收离线消息的方法中看一下,就知道了.

GOOGLE PROTOBUF开发者指南

原文地址:http://www.cppblog.com/liquidx/archive/2009/06/23/88366.html 译者: gashero 目录 1   概览 1.1   什么是protocol buffer 1.2   他们如何工作 1.3   为什么不用XML? 1.4   听起来像是为我的解决方案,如何开始? 1.5   一点历史 2   语言指导 2.1   定义一个消息类型 2.2   值类型 2.3   可选字段与缺省值 2.4   枚举 2.5   使用其他消息类型