Protocol buffers是google提供的一种将结构化数据进行序列化和反序列化的方法,其优点是语言中立,平台中立,可扩展性好,目前在google内部大量用于数据存储,通讯协议等方面。PB在功能上类似XML,但是序列化后的数据更小,解析更快,使用上更简单。用户只要按照proto语法在.proto文件中定义好数据的结构,就可以使用PB提供的工具(protoc)自动生成处理数据的代码,使用这些代码就能在程序中方便的通过各种数据流读写数据。PB目前支持Java, C++和Python3种语言。另外,PB还提供了很好的向后兼容,即旧版本的程序可以正常处理新版本的数据,新版本的程序也能正常处理旧版本的数据。我们主要研究PB在C++语言的使用,PB的编译安装比较简单,C++的库使用make完成,java使用maven完成,python直接使用setup命令完成。

Protocol Buffers要如何用在socket通信的通信协议中?可以大概地说一下:你需要根据你的协议编写一个.proto文件,此文件的格式是按Protocol Buffers的要求书写的。然后用Protocol Buffers编译器生成这个文件对应的类文件(包括一个.h文件和一个.cc文件),然后在你的程序中include生成的头文件,当需要发送socket消息的时候,先用这个类的对象的SerializeToString()方法,生成一个字符串,这个字符串也就相当于我们传统意义上的编码过的消息,然后在socket消息的接收方,使用ParseFromString()方法,就可以将消息中包含的数据解析到生成的类的成员变量中,就可以直接取出来用了。整个过程不需要你去考虑编码、解码,就算更改了协议,修改工作也非常方便。

零、为什么要研究ProtoBuff

需求是最大的驱动,加入百度Hi团队一个多月了,这一个多月的时间里做了许多以前没有做过的事。针对Hi用户的反馈,移动端Hi对流量的消耗太大。Hi消息传输的格式目前主要有2种,一种是公司定义的一种nshead+mcbody的形式,这种方式类似于我们今天所要讲解的ProtoBuff,统一使用这种方式也能够减小传输流量,而且数据安全性也更高;另一中方式就是比较古老的文本协议格式了。公司决定对现有的文本协议进行优化。怎么优化呢?Hi目前使用文本协议在客户端和服务端进行信息等传输,这里所说的消息包括CS之间Request包、ACK包,或者服务端的Notify包等等,这些包里面的包括的内容不仅仅是聊天信息,也包括联系人状态变更等各种通知信息。

总得来说,Hi消息传输的报文格式可以概括为:header + body,header主要由一些键值对构成,而body则更多的是使用xml的格式。最终决定使用高大上的ProtoBuff对当前的文本协议进行改进,在这里先列出具体的实现思路:

  1. 现有的消息包括header和body两个部分,我们需要一个转换工具,分析现有报文的定义要求,生成一个消息格式xml文件:即包括了header和body的一个xml文件;
  2. 根据该xml格式生成proto的描述文件,然后通过Proto编译生成对应的.h和.cc文件;
  3. 最后就是要考虑和现有协议的转换了,庞大的系统兼容性是不可忽略的,即服务端添加一个专门协议转换的模块,分别针对上行和下行进行原有报文到pb报文的相互转换。

一、ProtoBuff开发三部曲

所谓开发三部曲,即:

  1. 定义描述文件,即.proto文件;
  2. 使用proto编译器生成该描述文件对应的定义文件,C++包括.h和.cc;
  3. 使用定义文件中提供的ProtoBuff的API读写消息。

举个简单的实例,百度Hi在拉取群列表时的协议定义为group:get_list,我们在描述文件中定义如下:

我们如何去按照这个定义要求去封包呢?直接看代码:

上图中88行中的日志就是将我们的PB报文以字符串形式打印出来,便于我们调试,即DebugString方法。在日志中我们可到PB结构如下:

二、序列化与反序列化

继续看代码,我们已经准备好了PB的封包,序列化之后就可以通过连接发出去了

百度Hi-Server在接收到PB包之后通过一系列的处理,会返回一个group:get_list的ACK包回来,我们怎么把回包拿出来并转化成我们现有的文本协议形式呢?继续看代码:

红色框图中的部分就是反序列化的过程,通过反序列化之后,我们就可以调用ProtoBuff定义的API去解析该PB报文了。

三、完成协议的测试

我们的测试目的就是保证PB与原协议的兼容性,换句话说就是转换后的数据一致性,我们在ImpPacket中重载了==运算符,完成比较的过程,即分别对ImpPacket中的header和body做比较,header是由一些map构成的,body则是xml构成的。我们的比较就是分别对header和body中的map和xml进行比较。

xml的比较代码如下(部分):

这就是该博文的所有内容,6个不同的协议,耗时2天时间完成,期间还踩到老代码中的一个坑,gdb调试才定位到,累觉不爱。感谢阅读,Published by Windows LiveWriter.

筒子们,使用Protobuf优化你的协议的更多相关文章

  1. 【MINA】用protobuf做编解码协议

    SOCKET协议 支持java serial 与 AMF3的混合协议,目前没有基于xml 与 json的实现. 协议说明: * 9个字节协议头+协议体. * * 协议头1-4字节表示协议长度 =协议体 ...

  2. SuperSocket与Netty之实现protobuf协议,包括服务端和客户端

    今天准备给大家介绍一个c#服务器框架(SuperSocket)和一个c#客户端框架(SuperSocket.ClientEngine).这两个框架的作者是园区里面的江大渔. 首先感谢他的无私开源贡献. ...

  3. 使用Protobuf定义网络协议

    准备工具: 工具下载地址如下:https://github.com/protocolbuffers/protobuf/releases/tag/v3.6.1,主要使用到的文件有: protoc.exe ...

  4. 自定义兼容多种Protobuf协议的编解码器

    <从零开始搭建游戏服务器>自定义兼容多种Protobuf协议的编解码器 直接在protobuf序列化数据的前面,加上一个自定义的协议头,协议头里包含序列数据的长度和对应的数据类型,在数据解 ...

  5. Quick UDP Internet Connections 让互联网更快的协议,QUIC在腾讯的实践及性能优化

    https://mp.weixin.qq.com/s/44ysXnVBUq_nJByMyX9n5A 让互联网更快:通往QUIC之路 原创: 史天 翻译 云技术实践 8月15日 QUIC(Quick U ...

  6. 全面解密QQ红包技术方案:架构、技术实现、移动端优化、创新玩法等

    本文来自腾讯QQ技术团队工程师许灵锋.周海发的技术分享. 一.引言 自 2015 年春节以来,QQ 春节红包经历了企业红包(2015 年).刷一刷红包(2016 年)和 AR 红包(2017 年)几个 ...

  7. 微服务性能优化之thrift改造

    在我当前所做的web项目中,采用前后端分离模式前端通过Django 提供restful接口,后端采用微服务架构,微服务之间的调用采用jsonrpc,由于微服务之间的调用很频繁,导致前端得到的响应很慢, ...

  8. 转: 基于netty+ protobuf +spring + hibernate + jgroups开发的游戏服务端

    from: http://ybak.iteye.com/blog/1853335 基于netty+ protobuf +spring + hibernate + jgroups开发的游戏服务端 游戏服 ...

  9. NSCache和NSURLCache、网络缓存优化

    本文目录 一种缓存优化方案 响应头'Last-Modified'和请求头'If-Modified-Since' 'Keep-Alive'响应头和不离线的URLSession 'Expires'响应头 ...

随机推荐

  1. GWT-2.5.1离线安装

    GWT官方离线包下载地址 http://dl.google.com/eclipse/plugin/3.7/zips/gpe-e37-latest-updatesite.zip 以下是GWTDesign ...

  2. HDU 5095 Linearization of the kernel functions in SVM (坑水)

    比较坑的水题,首项前面的符号,-1,+1,只有数字项的时候要输出0. 感受一下这些数据 160 0 0 0 0 0 0 0 0 -10 0 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 ...

  3. Python-OpenCV——Image inverting

    通常我们将读入的彩色图转化成灰度图,需要将灰度图反转得到掩码,如何正确快速的得到某个图像的反转图呢? 首先看一种看似很正确的写法,对其中每个像素进行如下处理: img[x,y] = abs(img[x ...

  4. VS开发软winform软件的更改用户使用权限

    在使用软件的过程中,我们经常需要使用的软件拥有管理员权限,在开发的过程中,本人就遇到了应为权限不足的问题导致软件不能正常使用的状况. 在此我来记录我遇到的问题. 为开发的软件赋予管理员权限 https ...

  5. Hibernate异常:identifier of an instance of 错误

    今天写项目时,在使用hibernate封装的插入方法时,由于需要同时保存多个数据,导致出现identifier of an instance of 如下代码 :(由于最大最小分数不同所以需要插入两条数 ...

  6. 判断是否是同一人的方法——equals()?在Person类中提供一个比较的方法compare()返回boolean值?对象自己和自己比?

    判断是否是同一人的方法——equals() 不能直接用per1==per2,这不是对象内容的比较而是存放对象地址的值得比较 在Person类中提供一个比较的方法compare()返回boolean值 ...

  7. Element表单验证(2)

    Element表单验证(2) 上篇讲的是async-validator的基本要素,那么,如何使用到Element中以及怎样优雅地使用,就在本篇. 上篇讲到async-validator由3大部分组成 ...

  8. 第一本C语言笔记(下)

    11. 数组 (1)数组初始化时,如果初始化数字个数超过存储区个数,就忽略多余数字.如果初始化数字个数少于存储区个数,则后面的存储区自动被初始化为0. (2)数组名称可以代表数组里第一个存储区的地址. ...

  9. Linux系统修改网卡名(eth0-3)

    一.命名规则策略 规则1: 对于板载设备命名合并固件或 BIOS 提供的索引号,如果来自固件或 BIOS 的信息可读就命名,比如eno1,这种命名是比较常见的,否则使用规则2. 规则2: 命名合并固件 ...

  10. Jenkins忘记管理员密码处理

    1.先找到jenkins安装目录打开config.xml文件. 2.然后编辑,删除以下部分: <useSecurity>true</useSecurity> <autho ...