protobuf那些事
大家好,俺又来写博客了.......上次剧情预告说,这次会写hive的博客.......好吧,那俺就不打算写hive了.......老码农路子就是要野(本人不老,不能说得影响了找女票)......这次咱们玩什么呢,我之前就看重了一个比较好玩的小玩意儿,那就是来自google的技术,protobuf.
上次的博客我看了之后很失望啊,阅读数并不高....我在想是不是大家对hadoop之类的并不感兴趣,所以就先换换口味吧.Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,目前已经正在使用的有超过 48,162 种报文格式定义和超过 12,183 个 .proto 文件。他们用于 RPC 系统和持续数据存储系统。Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 三种语言的 API。
ok,这就是protubuf的一些比较抽象的介绍,不过简单地说,protobuf其实就是一种数据传输的格式,事实上,我们需要知道pb这种格式用来传输数据到底会给我们带来如何的好处.我们可以拿pb格式和json做对比.其实json这种数据传输的格式大家应该非常熟悉.但是json有什么不好的呢,首先json大,json格式是字符串形式,和压缩为二进制的pb格式肯定是要来的大的.此外,json很坑,因为需要对不同的语言编写json解析的程序.......php和python自然可以比较轻松的解析,java就坑了.......而且这些解析器的性能并一致,有好有坏.pb因为是大厂的技术嘛,人家搞一个编译器,编译为c++,java,python的解析代码,不就搞定了.......好吧,大厂技术就是雄厚.......我等也只能仰望.....(老子要是有时间,也去写一个)....
废话不多说,直接搞起来.首先,你要去下载pb的tar包.至于安装包在哪里,少年郎,去google上找吧........我装的是2.6.1版,安装非常简单.
tar zxvf protobuf-2.6..tar.gz
cd protobuf-2.6.
./configure
make
make check
make install
这个编译的过程依旧是无比的漫长.......很怀念大一的时候,写个hello world,一秒不到就编译完成,然后很快就能输出结果的那种快乐的时光.........人的一生就是在等待中度过,等待一个可以白头到老的人,等待一份可以吃饱饭的工作,等待有一天,能够成为想成为的那个人.......其实等待是因为有希望,没有希望,等待似乎就没有意义了......所以,我一直在想,女票是会有的,饭也可以吃饱的,人不能没有希望........
ok,我们安装完了,来看看有没有安装上吧......
protoc --version
返回:libprotoc 2.6.1. 这样,就安装成功了.
然后我们怎么用这个工具呢?
- 首先,我们要做的是,定义一套.proto格式的消息的定义文件.我们在具体的使用中来慢慢来港如何书写这个proto缀的文件.
message student{
required int64 sid = ;//学生id
required string name = ;//学生姓名
}
这里面我们发现:
- message类似于C里面的struct,表示我们定义的是一个消息类型.
- studeng是具体的类型名称.
- required是表示这个字段是必须赋值的.
- int64和string是该字段的类型.
- =后面的数字表示是该字段在二进制文件中的序号,name为2,表示它一定在sid的后面.
现在我们如果想要加上一个性别的字段和年龄的字段,性别的字段是enum类型.年龄类型是int32,怎喵加呢?很简单.
enum Sex{
MALE = ;
FEMALE = ;
} message Student{
required int64 sid = ;//学生id
required string name = ;//学生姓名
optional Sex sex = ; //学生性别
optional int32 age = ;//学生年纪
}
easy啊.等等,现在我们又有一个消息,比如我们有个班级的消息,希望能够列出里面每个学生的这些基本信息,怎么搞呢?
首先,我们需要定义一个班级的消息.
message Banji{
required int64 cid = ;//班级的id
required string cname = ;//班级的编号
repeated Student students = ;//学生
}
这里我们要注意几个点:
- required前缀表示该字段为必要字段,既在序列化和反序列化之前该字段必须已经被赋值。与此同时,在Protocol Buffer中还存在另外两个类似的关键字,optional和repeated,带有这两种限定符的消息字段则没有required字段这样的限制。
- 标签值为1到15的字段在编码时可以得到优化,既标签值和类型信息仅占有一个byte.标签范围是16到2047的将占有两个bytes,而ProtocolBuffer可以支持的字段数量则为2的29次方减一。有鉴于此,我们在设计消息结构时,可以尽可能考虑让repeated类型的字段标签位于1到15之间,这样便可以有效的节省编码后的字节数量。
- 在每个消息中必须至少留有一个required类型的字段.
- 如果打算在原有消息协议中添加新的字段,同时还要保证老版本的程序能够正常读取或写入,那么对于新添加的字段必须是optional或repeated。道理非常简单,老版本程序无法读取或写入新增的required限定符的字段。
- 在原有的消息中,不能移除已经存在的required字段,optional和repeated类型的字段可以被移除,但是他们之前使用的标签号必须被保留,不能被新的字段重用。
- int32、uint32、int64、uint64和bool等类型之间是兼容的,sint32和sint64是兼容的,string和bytes是兼容的,fixed32和sfixed32,以及fixed64和sfixed64之间是兼容的,这意味着如果想修改原有字段的类型时,为了保证兼容性,只能将其修改为与其原有类型兼容的类型,否则就将打破新老消息格式的兼容性。
这里还有一个问题,Banji这个消息要用到Student的定义,我们可以回忆一下java中的处理方式,这种互相定义之间的依赖可以用package和import来解决.这样,我们可以给出完整的.proto的定义方式:
test.student.proto
package test;
option java_package = "com.songfy.pb";
option java_outer_classname = "StudentProtobuf";
enum Sex{
MALE = 1;
FEMALE = 2;
} message Student{
required int64 sid = 1;//学生id
required string name = 2;//学生姓名
optional Sex sex = 3; //学生性别
optional int32 age = 4;//学生年纪
}
test.banji.proto
import "test.student.proto";
package test;
option java_package = "com.songfy.pb";
option java_outer_classname = "BanjiProtobuf";
message Banji{
required int64 cid = 1;//班级的id
required string cname = 2;//班级的编号
repeated Student students = 3;//学生
}
ok,这样我们就把我们的消息类型定义好了....那么如何写代码呢?下面我们细细道来.
2.编译.proto
我们这里用java来做示例,C++也成,但是还是java稍微方便一下,大家可以用C++试一试,python呢就算了,俺不太会python,也没有兴趣去学,个人喜好,勿喷,嗯,就这样.ok,那现在我们就来编译这个玩意儿.
protoc --java_out="/usr/home/feng/protos/src" test.banji.proto test.student.proto
吊炸天,瞬间产生了1000多行代码,来自google的技术,四国一!
不过现在问题来了,这代码怎么用?这代码看都看不懂,怎么用呢?不要惊慌,一定不要惊慌.......先靠到你的elipse再说....然后你就会发现一大堆的错误......嗯........
这个解决的方法很简单,将protobuf-java-2.6.1.jar下载下来,加入到我们的path中,那我们的问题就都解决了.
接下来,我们来看看如何写代码.嗯,终于到了写代码的时候了........
package com.songfy.pb; import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import com.songfy.pb.BanjiProtobuf.Banji;
import com.songfy.pb.StudentProtobuf.Sex;
import com.songfy.pb.StudentProtobuf.Student; public class Main { public static void main(String[] args) throws IOException { //获取student的build sb
Student.Builder sb = Student.newBuilder();
//加入两个学生
sb.setSid(110);
sb.setName("shuaiguo");
sb.setSex(Sex.MALE);
sb.setAge(11); List<Student> list = new ArrayList<Student>();
list.add(sb.build()); sb = Student.newBuilder();
sb.setSid(119);
sb.setName("lilei");
sb.setSex(Sex.FEMALE);
sb.setAge(20); list.add(sb.build()); //产生一个班级
Banji.Builder bb = Banji.newBuilder();
bb.setCid(13);
bb.setCname("dafengqi");
bb.addAllStudents(list); //刷入到文件中
FileOutputStream fos = new FileOutputStream("C:/Users/songfy/Desktop/test.protoout");
bb.build().writeTo(fos);
fos.close(); //从文件读回
Banji bb1 = Banji.parseFrom(new FileInputStream("C:/Users/songfy/Desktop/test.protoout"));
System.out.println(bb1.getCid() + "\t" + bb1.getCname());
for(Student s: bb1.getStudentsList()){
System.out.println(s.getSid() + "\t" + s.getName() + "\t" + s.getSex() + "\t" + s.getAge());
} } }
这就是我们代码了,似乎非常easy啊........
这样,我们可以看到输出结果为:
13 dafengqi
110 shuaiguo MALE 11
119 lilei FEMALE 20
这正是我们想要的,这次的博客时间就到此为止了,我们下次再见........2333333......2333333.......
protobuf那些事的更多相关文章
- GOOGLE PROTOBUF开发者指南
原文地址:http://www.cppblog.com/liquidx/archive/2009/06/23/88366.html 译者: gashero 目录 1 概览 1.1 什么是pro ...
- rpc框架: thrift/avro/protobuf 之maven插件生成java类
thrift.avro.probobuf 这几个rpc框架的基本思想都差不多,先定义IDL文件,然后由各自的编译器(或maven插件)生成目标语言的源代码,但是,根据idl生成源代码这件事,如果每次都 ...
- 基于protobuf的RPC实现
可以比较使用google protobuf RPC实现echo service可见.述. google protobuf仅仅负责消息的打包和解包.并不包括RPC的实现.但其包括了RPC的定义.如果有以 ...
- protobuf与json互相转换
Java http://code.google.com/p/protobuf-java-format/ maven <dependency> <groupId>com.goog ...
- 解决Protobuf生成的C#代码命名不规范问题
起因 通常使用Protobuf的步骤为 定义 .proto 文件 使用 protoc 生成对应语言的代码 以生成C#代码为例,使用如下命令: protoc -I ../protos --csharp_ ...
- [Todo]对于thrift和protobuf比较好的描述
比较跨语言通讯框架:thrift和Protobuf 全部thrift protobuf 前两天想在微博上发表一个观点:在现在的技术体系中,能用于描述通讯协议的方式很多,xml,json,protobu ...
- 聊聊iOS中网络编程长连接的那些事
1.长连接在iOS开发中的应用 常见的短连接应用场景:一般的App的网络请求都是基于Http1.0进行的,使用的是NSURLConnection.NSURLSession或者是AFNetworking ...
- 【迷你微信】基于MINA、Hibernate、Spring、Protobuf的即时聊天系统:0.概述
欢迎阅读我的开源项目<迷你微信>服务器与<迷你微信>客户端 序言 帖主和队友仿制了一个简单版的微信,其中,队友是用Unity3D做前段,帖主用Java的Mina.Hiberna ...
- h5 录音 自动生成proto Js语句 UglifyJS-- 对你的js做了什么 【原码笔记】-- protobuf.js 与 Long.js 【微信开发】-- 发送模板消息 能编程与会编程 vue2入坑随记(二) -- 自定义动态组件 微信上传图片
得益于前辈的分享,做了一个h5录音的demo.效果图如下: 点击开始录音会先弹出确认框: 首次确认允许后,再次录音不需要再确认,但如果用户点击禁止,则无法录音: 点击发送 将录音内容发送到对话框中.点 ...
随机推荐
- 较简单的用ajax修改和添加功能(链接数据库)
修改和添加关于数据库的信息,可以用于任何的添加和修改 这些数据库和前面的随笔数据库是一样的 一.显示出数据库中的信息 (1)显示的效果也可以是用bootstrap的标签页显示(前面一定要引入boots ...
- Eclipse中将含有图片资源的项目打包成jar文件
前言: 最近学了GUI编程和UDP协议,心血来潮想做一个局域网内的聊天软件,前期都还算顺利,直到后来将整个项目打包成jar文件时遇到了困难.如图: 自己设置的图标不见了,但是也没有默认的图标,说明图片 ...
- Excel 按模板格式导出
最近遇到一个问题,就是导出数据的时候需要自定义的表头,如图 如果自己用代码写表头的话,可能会有点复杂,而且代码量很多,所以我就想了一个办法,直接在Excel里面把表头定义好,然后把数据写入Excel模 ...
- Python之路-操作系统&网络基础
一.为何要有操作系统 没有操作系统的话,计算机同样可以运行,但是程序员要了解到计算机底层各种各样的细节,而操作系统聪明地封装起来了底层这些繁杂的操作,通过向程序员开放一个个的接口,来最终使我们实现对底 ...
- 老李推荐: 第1章1节《MonkeyRunner源码剖析》概述:前言
老李推荐: 第1章1节<MonkeyRunner源码剖析>概述:前言 前言 相信大家做过安卓移动平台UI自动化开发的必然会用过,至少听过MonkeyRunner这个名字.MonkeyR ...
- 程序设计 之 C#实现《拼图游戏》
功能描述: 1.用户自定义上传图片 2.游戏难度选择:简单(3*3).一般(5*5).困难(9*9)三个级别 3.纪录完成步数 模块: 1.拼图类 2.配置类 3.游戏菜单窗口 4.游戏运行窗口 -- ...
- Linux:一位猫奴的意外产物
作者:Vamei,严禁任何形式转载. 1991年年中,林纳斯·托瓦兹(Linus Torvalds)在自己房间里敲着键盘.他全神贯注地盯着14寸的黑色屏幕,都没感觉到自己的小猫Randi在扒自己的裤腿 ...
- Historical节点
Historical节点 Historical 节点的作用是,load 历史数据提供查询. 运行类 io.druid.cli.Main server historical 装载和保存Segments ...
- docker.service启动失败:Unit not found
docker.service启动失败:Unit not found 版权声明:本文为博主原创文章,未经博主允许不得转载. 背景 因为最近一直在折腾Kubernetes集群版本升级.Docker版本升级 ...
- java面试题—精选30道Java笔试题解答(一)
下面都是我自己的答案非官方,仅供参考,如果有疑问或错误请一定要提出来,大家一起进步啦~~~ 1. 下面哪些是Thread类的方法() A start() B run() C exit() D getP ...