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. UESTC 1307 WINDY数 (数位DP,基础)

    题意: windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数.windy想知道,在A和B之间,包括A和B,总共有多少个windy数? 思路: 就是给连续的两 ...

  2. Android(java)学习笔记138:三重for循环的优化(Java面试题)

    1. 首先我们看一段代码: for(int i=0;i<1000;i++){ for(int j=0;j<100;j++){ for(int k=0;k<10;k++){ testF ...

  3. python_91_正则表达式

    常用的正则表达式: '.' 默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行 '^' 匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r& ...

  4. Java 从资源文件(.properties)中读取数据

    在Java工程目录src下,创建一个后缀为.properties的文件,例如db.properties 文件中的内容如下(键=值): name=mk age=123 address=China 在程序 ...

  5. Bootstrap 下拉菜单(dropdown)插件

    使用下拉菜单的插件,您可以向任何组件(比如:导航栏,标签页,胶囊式导航,按钮)添加下拉菜单 用法 您可以切换下拉菜单(dropdown)插件隐藏内容 1.通过data属性,向链接或按钮添加data-t ...

  6. 远程连接 mySql数据库

    远程连接 mySql数据库 一.安装并配置MySQL1.安装MySQL:运行mysql-essential-6.0.11-alpha-win32,按“MySQL+6.0+Windows下安装图解”完成 ...

  7. 【模板】无旋Treap(FHQ)

    如题,这是一个模板... #include <algorithm> #include <iostream> #include <cstring> #include ...

  8. Linux常用快捷键以及如何查看命令帮助

    1.1    Linux系统快速操作常用快捷键 快捷键名称 快捷作用 Ctrl + a 将光标移至行首 Ctrl + e 将光标移至行尾 Ctrl + u 前提光标在行尾,则清除当前行所有的内容(有空 ...

  9. destoon手机端mobileurl函数增加城市分类参数

    mobileurl函数在include/global.func.php 858行 共四个参数,moduleid-模型id,catid-分类id,itemid -文章id,page-页码 functio ...

  10. url,href,src区别

    URL(Uniform Resource Locator) 统一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址.互联网上的每个文件都有一个唯一的URL ...