最近在读别人代码的时候发现一个的东西,名字叫protobuf, 感觉挺好用的,写在这里,留个记录。那么什么是protobuf 呢?假如您在网上搜索,应该会得到类似这样的文字介绍:

Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,目前已经正在使用的有超过 48,162 种报文格式定义和超过 12,183 个 .proto 文件。他们用于 RPC 系统和持续数据存储系统。

Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 三种语言的 API。

说的明白点,它其实是一个可以帮你生成自定义数据结构的代码,并提供了序列化该结构的方法,并且支持多语言,跨平台等一系列优点。多说无益,直接说说该怎么用它。

首先 你需要编写proto文件,在这个文件中 用简单的方法定义了你想要定义的数据结构的组成信息。比如定义一个helloworld的信息,里面包含name, password, email 这三个信息。那么你的proto文件应该是这个样子的:

package im;
message helloworld
{
  required string usrname = 1;
  required string passwd = 2;
  optional string email = 3;
}

im 说明了包的名称, helloworld 说明了 具体的结构类型。 一个比较好的习惯是认真对待 proto 文件的文件名。比如将命名规则定于如下:packageName.MessageName.proto

接下来 你需要运行一个命令来来生成该数据结构的代码

假设您的 proto 文件存放在 $SRC_DIR 下面,您也想把生成的文件放在同一个目录下,则可以使用如下命令:

protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/im.helloworld.proto

那么这个时候你就会在DST_DIR下面看到im.helloworld.pb.h  im.helloworld.pb.cpp

此时基本就大功告成了,你就可以在你的代码里使用关于helloworld这个数据结构的一切了。

这个工具主要比较方便的地方是它给你提供的序列化工具。可以直接将一个数据结构序列化为字符、或者从字符反序列化为数据结构。你想,这就为很多的网络程序提供了方便,在客户机在向服务端传递消息的时候可以直接将需要传递的消息用一个数据结构封装,然后用protobuf提供的序列化方法,序列化为一个字符串,然后你人为的加一个包头(包含消息的长度和消息的类型)做一次encode;在服务端接收该消息的时候根据encode的方法对包进行接收,接收完之后再用protobuf提供的反序列化方法,从字符串再次还原为具体的数据结构信息。整个过程就不需要你去造轮子去做那些繁琐的字符解析拼装的工作了,是不是很爽? 这个我认为是protobuf比较有用的地方之一,另外一个比较有用的地方是,它可以根据类型信息去create对象,比如 之前我定义的helloworld结构,假如我现在在做一个服务端的程序,我想实现这样的一个功能,在接收到helloworld消息的时候,我去执行相应的helloworld回调。当然对于helloworld的回调是在系统启动的时候加载的。这样有一个好处,实现整个系统的模块化,并且耦合度也很低。没有这个工具的话,我可能就需要在解析的时候特别的关注收到的消息类型字段,然后根据该字段去new一个相应的对象,进而调用相应的处理过程,整个过程都需要你去手写,有了protobuf,你完全不需要造轮子了。

那么怎么样根据消息的类型直接创建相应的对象呢?代码如下:

google::protobuf::Message* create_message(const std::string& type_name)
{
  google::protobuf::Message* message = NULL;
  const google::protobuf::Descriptor* descriptor = \
  google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(type_name);
  if(descriptor)
  {
    const google::protobuf::Message* prototype =
      google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor);
    if(prototype)
    {
      message = prototype->New();
    }
  }
  return message;
}

有点设计模式里工厂模式的味道。在消息的种类不多的时候,你可以感觉不到它的好处,但在你的系统越来越庞大的时候,你自然能体会到这个小小函数的甜头。

在你知道消息类型,并根据这个工具生成消息对象的时候,接下来就该处理了,也就是dispatch。上面我有提到过,你可以注册每个消息类型的回调处理方法,通俗点讲就是你的系统里需要有一个map,这个map里存储了不同消息的处理方法,类似于:

std::map<std::string, message_callback_t>  _message_callbacks; 这样的一个容器。具体的方法如下:

void deal_message(google::protobuf::Message* msg)
{
  auto iter_map = _message_callbacks.find(msg->GetTypeName()); //得到消息的具体类型,protobuf提供的内置方法
  if(iter_map != _message_callbacks.end())
  {
    iter_map->second(msg);  //相应的回调处理
  }
  else
  {
    std::cout << "message dealer no found" << std::endl;
  }
}

你看这样是不是简直帅呆了,你的系统如果用这样的方法来执行消息分发处理,整个系统将会变得很清晰,模块间耦合很低。

基于以上的思路,我简单实现了一个client和server,来示例本博文的思路,源代码地址:https://github.com/xiaopeifeng/CodeTricks/tree/master/protobuf

欢迎指正批评。

google protobuf初体验的更多相关文章

  1. protobuf初体验

    概念介绍 Protocol buffers 是google公司的与语言无关.与平台无关的.可扩张的为序列化话结构数据,就像xml一样,办事更加的小巧.快速.简单.Protocol buffers 目前 ...

  2. protobuf(Protocol Buffers)java初体验

    因为项目须要所以简单的研究了下protobuf.我也是參照网上的博客,所以大部分内容我也就不反复造轮子了.首先protobuf介绍点击这里,使用介绍点击这里,使用demo看这里. 我个人的第一个样例也 ...

  3. ASP.NET Core 3.0 上的gRPC服务模板初体验(多图)

    早就听说ASP.NET Core 3.0中引入了gRPC的服务模板,正好趁着家里电脑刚做了新系统,然后装了VS2019的功夫来体验一把.同时记录体验的过程.如果你也想按照本文的步骤体验的话,那你得先安 ...

  4. Xamarin.iOS开发初体验

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKwAAAA+CAIAAAA5/WfHAAAJrklEQVR4nO2c/VdTRxrH+wfdU84pW0

  5. win7升win10,初体验

    跟宿舍哥们聊着聊着,聊到最近发布正式版的win10,听网上各种评论,吐槽,撒花的,想想,倒不如自己升级一下看看,反正不喜欢还可以还原.于是就开始了win10的初体验了,像之前装黑苹果双系统一样的兴奋, ...

  6. python--爬虫入门(七)urllib库初体验以及中文编码问题的探讨

    python系列均基于python3.4环境 ---------@_@? --------------------------------------------------------------- ...

  7. Java8初体验(一)lambda表达式语法

    感谢同事[天锦]的投稿.投稿请联系 tengfei@ifeve.com 本文主要记录自己学习Java8的历程,方便大家一起探讨和自己的备忘.因为本人也是刚刚开始学习Java8,所以文中肯定有错误和理解 ...

  8. node.js 初体验

    node.js 初体验 2011-10-31 22:56 by 聂微东, 174545 阅读, 118 评论, 收藏, 编辑 PS: ~ 此篇文章的进阶内容在为<Nodejs初阶之express ...

  9. YII学习,初体验 ,对YII的一些理解.

    先说点没用的: 不会选择,选择后不坚持,不断的选择.这是人生中的一个死循环,前两一直迷茫.觉得自己前进方向很不明朗.想去学的东西有很多.想学好YII,想学PYTHON 想学学hadoop什么的,又想研 ...

随机推荐

  1. 面向对象(五)super

    super方法只是为了执行继承父级的init方法,若要详细,请参考别人的博客 class a(object): def __init__(self): print("aINIT") ...

  2. core dump 是什么意思?

    core dump,翻译过来讲,就是核心转储.大致上就是指,如果由于应用错误,如浮点异常.指令异常等,操作系统将会转入内核的异常处理,向对应的进程发送特定的信号(SIGNAL),如果进程中没有对这些信 ...

  3. 【krpano】浏览点赞插件(源码+介绍+预览)

    简介 最近几天研究了如何在krpano全景的基础上实现记录浏览量和点赞次数,写了一个插件,方便大家使用. 效果截图如下: 每当有用户打开该全景页面时,浏览量会自动加1: 用户可以主动点击点赞按钮,点击 ...

  4. c语言libcurl库的异步用法

    multi接口的使用会比easy 接口稍微复杂点,毕竟multi接口是依赖easy接口的,首先粗略的讲下其使用流程:curl_multi _init初始化一个multi curl对象,为了同时进行多个 ...

  5. SQL入门语句之CREATE

    一.CREATE DATABASE语句 1.创建一个SQL数据库 CREATE DATABASE database_name 二.CREATE TABLE语句 1.只创建字段和相对应的数据类型 cre ...

  6. Swift - 进度条(UIProgressView)的用法

    1,创建进度条 1 2 3 4 var progressView=UIProgressView(progressViewStyle:UIProgressViewStyle.Default) progr ...

  7. 【MongoDB】 基于C#官方驱动2.2版的封装类

    一.前言 最近项目中要用到MongoDB,因此实现做了不少的调研.发现网上很多现有关于MongoDB C#官方驱动的调用方法都是基于1.8版本的,已经不是用了最新的2.2版本.因此我在基于C#官方驱动 ...

  8. HDU 2082 找单词 (多重背包)

    题意:假设有x1个字母A, x2个字母B,..... x26个字母Z,同时假设字母A的价值为1,字母B的价值为2,..... 字母Z的价值为26.那么,对于给定的字母,可以找到多少价值<=50的 ...

  9. curl运行json串,代理转发格式

    curl -b 'uin=o0450654733; skey=@tq9xjRvYy' -H "Content-Type: application/json" -X POST -d ...

  10. js函数封装

    1.随机数 <script> function rnd(n,m){ return parseInt(Math.random()*(m-n)+n); } var a=rnd(45,47); ...