RPC框架系列——Protocol Buffers
http://blog.jeoygin.org/2011/09/rpc-framework-protocol-buffers.html
1.下载与安装
官方网站:http://code.google.com/p/protobuf/
下载地址:http://protobuf.googlecode.com/files/protobuf-2.4.1.tar.bz2
protocol buffers并没有实现RPC通信,可以使用第三方的RPC实现protobuf-socket-rpc,下载地址是:http://protobuf-socket-rpc.googlecode.com/files/protobuf-socket-rpc-2.0.jar
- cd /usr/local/src
- wget http://protobuf.googlecode.com/files/protobuf-2.4.1.tar.bz2
- tar jxvf protobuf-2.4.1.tar.bz2
- cd protobuf-2.4.1
- ./configure
- make
- make check
- make install
下面将编译生成jar包,以便在java中使用Protocol Buffers,需确保已安装了maven。
- cd java
- mvn test
- mvn install
- mvn package
安装、编译后在target/目录下会生成protobuf-java-2.4.1.jar。
2.消息结构与服务接口
首先需要编写一个.proto文件,结构化数据被称为Message。
- package protobuf;
- option java_package = "protobuf";
- option java_outer_classname = "PersonProtos";
- option java_generic_services = true;
- message Person {
- required string name = 1;
- required int32 id = 2;
- optional string email = 3;
- enum PhoneType {
- MOBILE = 0;
- HOME = 1;
- WORK = 2;
- }
- message PhoneNumber {
- required string number = 1;
- optional PhoneType type = 2 [default = HOME];
- }
- repeated PhoneNumber phone = 4;
- service PhoneService {
- rpc GetPhone (Phone) returns (Phone);
- }
- }
消息的成员需要指定其规则:
(1) required:这个域在消息中必须刚好有1个;
(2) optional:这个域在消息中可以有0或1个;
(3) repeated:这个域在消息中可以有从多个,包括0个。
Protobuf的类型与Java类型的映射关系:
- double -> double
- float -> float
- int32 -> int
- int64 -> long
- uint32 -> int[1]
- uint64 -> long[1]
- sint32 -> int
- sint64 -> long
- fixed32 -> int[1]
- fixed64 -> long[1]
- sfixed32 -> int
- sfixed64 -> long
- bool -> boolean
- string -> String
- bytes -> ByteString
编写完.proto文件后,就可以使用下面的命令将会在protobuf目录中生成源文件PersonProtos.java
- protoc –java_out=. person.proto
3.序列化
先看下面一个例子:
- message Test1 {
- required int32 a = 1;
- }
创建一个Test1消息,并且把a设置为150,那么序列化后有如下3个字节:
- 08 96 01
3.1.varint编码
varint编码的序列化使用一个或多个字节,数字越大使用的字节数越多。对于序列化后的字节,除了最后一个字节,都有一个most significant bit(msb):表示后边是否有更多的字节。整数序列化时按7位一组,每个字节的低7位保存一组,第一个字节存储最低位一组,即使用little endian。
比如300序列化后的字节序列是:
- 10101100 00000010
先去掉每个字节的msb:
- 0101100 0000010
交换字节的顺序:
- 0000010 0101100 -> 100101100 -> 256 + 32 + 8 + 4 = 300
3.2.消息结构
一个protocol buffer message是一个key/value对序列。每一key/value对的key实际是两个值:.proto文件中的field number以及wire type。可用的wire type如下所示:
Type | Meaning | Used For |
0 | Varint | int32, int64, uint32, uint64, sint32, sint64, bool, enum |
1 | 64-bit | fixed64, sfixed64, double |
2 | Length-delimited | string, bytes, embedded messages, packed repeated fields |
3 | Start group | groups (deprecated) |
4 | End group | groups (deprecated) |
5 | 32-bit | fixed32, sfixed32, float |
每一个key是一个varint,值是(field_number << 3) | wire_type,即低三位存储wire type。
3.3.有符号整数
有符号整数使用ZigZag编码来将有符号整数映射到无符号整数。
Signed Original | Encoded As |
0 | 0 |
-1 | 1 |
1 | 2 |
-2 | 3 |
2147483647 | 4294967294 |
-2147483648 | 4294967294 |
3.4.非varint编码
- message Test2 {
- required string b = 2;
- }
将b的值设置为“testing”,编码结果为:
- 12 07 74 65 73 74 69 6e 67
这里的key是0×12:field_number = 2, type = 2。字符串的长度是7。
3.5.嵌套消息
- message Tes3 {
- required Test1 c = 3;
- }
c的成员a的值设置为150,编码结果为:
- 1a 03 08 96 01
后三个字节和Test1一样,之前的数字3表示长度。
3.5.Repeated域
- message Test4 {
- repeated int32 d = 4;
- }
{3, 270, 86942}编码结果为:
- 22 // tag (field number 4, wire type 2)
- 06 // payload size (6 bytes)
- 03 // first element (varint 3)
- 8E 02 // second element (varint 270)
- 9E A7 05 // third element (varint 86942)
4.rpc通信实现
使用protocol buffers的第三方rpc实现protobuf-socket-rpc。
假设protocol buffers生成的类是protobuf. MessageProtos,其中定义了一个消息类Message和一个服务类MessageService,MessageService中定义了一个接口getMessage(RpcController, Message request)。
服务接口实现MessageServiceImpl.java:
- packageprotobuf;
- importcom.google.protobuf.RpcController;
- importcom.google.protobuf.ServiceException;
- importprotobuf.MessageProtos.Message;
- importprotobuf.MessageProtos.MessageService.BlockingInterface;
- publicclassMessageServiceImplimplementsBlockingInterface{
- @Override
- publicMessagegetMessage(RpcControllercontroller,Messagerequest)
- throwsServiceException{
- // process request
- ……
- returnrequest;
- }
- }
服务端实现Server.java:
- packageprotobuf;
- importjava.util.concurrent.Executors;
- importcom.googlecode.protobuf.socketrpc.RpcServer;
- importcom.googlecode.protobuf.socketrpc.ServerRpcConnectionFactory;
- importcom.googlecode.protobuf.socketrpc.SocketRpcConnectionFactories;
- importprotobuf.MessageProtos.MessageService;
- publicclassServer{
- privateintport;
- privateintthreadPoolSize;
- publicServer(intport,intthreadPoolSize){
- this.port=port;
- this.threadPoolSize=threadPoolSize;
- }
- publicvoidrun(){
- // Start server
- ServerRpcConnectionFactoryrpcConnectionFactory=SocketRpcConnectionFactories
- .createServerRpcConnectionFactory(port);
- RpcServerserver=newRpcServer(rpcConnectionFactory,
- Executors.newFixedThreadPool(threadPoolSize),true);
- server.registerBlockingService(MessageService
- .newReflectiveBlockingService(newMessageServiceImpl()));
- server.run();
- }
- publicstaticvoidmain(String[]args){
- if(args.length!=2){
- System.out.println("Usage: Server port thread_pool_size");
- return;
- }
- intport=Integer.parseInt(args[0]);
- intsize=Integer.parseInt(args[1]);
- newServer(port,size).run();
- }
- }
客户端实现Client.java:
- packageprotobuf;
- importprotobuf.MessageProtos.Message;
- importprotobuf.MessageProtos.MessageService;
- importprotobuf.MessageProtos.MessageService.BlockingInterface;
- importcom.google.protobuf.BlockingRpcChannel;
- importcom.google.protobuf.ByteString;
- importcom.google.protobuf.RpcController;
- importcom.google.protobuf.ServiceException;
- importcom.googlecode.protobuf.socketrpc.RpcChannels;
- importcom.googlecode.protobuf.socketrpc.RpcConnectionFactory;
- importcom.googlecode.protobuf.socketrpc.SocketRpcConnectionFactories;
- importcom.googlecode.protobuf.socketrpc.SocketRpcController;
- publicclassClient{
- privateintport;
- privateStringhost;
- privateintsize;
- privateintcount;
- publicClient(intport,Stringhost,intsize,intcount){
- super();
- this.port=port;
- this.host=host;
- this.size=size;
- this.count=count;
- }
- publiclongrun(){
- // Create channel
- RpcConnectionFactoryconnectionFactory=SocketRpcConnectionFactories
- .createRpcConnectionFactory(host,port);
- BlockingRpcChannelchannel=RpcChannels
- .newBlockingRpcChannel(connectionFactory);
- // Call service
- BlockingInterfaceservice=MessageService.newBlockingStub(channel);
- RpcControllercontroller=newSocketRpcController();
- Message.Buildermessage=Message.newBuilder();
- // initiate the message
- …
- longstart=0;
- longend=0;
- try{
- start=System.currentTimeMillis();
- for(inti=0;i<count;i++){
- service.getMessage(controller,message.build());
- }
- end=System.currentTimeMillis();
- System.out.println(end-start);
- }catch(ServiceExceptione){
- e.printStackTrace();
- }
- // Check success
- if(controller.failed()){
- System.err.println(String.format("Rpc failed %s : %s",
- ((SocketRpcController)controller).errorReason(),
- controller.errorText()));
- }
- returnend-start;
- }
- publicstaticvoidmain(String[]args){
- if(args.length!=4){
- System.out.println("Usage: Client host port dataSize count");
- return;
- }
- Stringhost=args[0];
- intport=Integer.parseInt(args[1]);
- intsize=Integer.parseInt(args[2]);
- intcount=Integer.parseInt(args[3]);
- newClient(port,host,size,count).run();
- }
- }
5.参考资料
(1) Protocol Buffers Documentation: http://code.google.com/apis/protocolbuffers/docs/overview.html
RPC框架系列——Protocol Buffers相关推荐
- RPC框架系列——Avro
1.下载与安装 官方网站:http://avro.apache.org/ 下载地址:http://labs.renren.com/apache-mirror//avro/avro-1.5.1/avro ...
- RPC框架系列MessagePack
1.下载与安装 官方网站:http://msgpack.org/ 下载地址:https://github.com/msgpack/msgpack-rpc, https://github.com/msg ...
- 阿里首席架构师科普RPC框架是什么
2019独角兽企业重金招聘Python工程师标准>>> RPC概念及分类 RPC全称为Remote Procedure Call,翻译过来为"远程过程调用".目前 ...
- Protocol Buffers proto语言语法说明
原文地址:http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/proto.html proto语言有自己的 数据类型(Field T ...
- 使用Akka实现简单RPC框架
使用Akka实现简单RPC框架 最近简单看了看Flink的RPC通讯相关的源码,它是通过Akka实现的,为了更好的阅读理解代码,又大体看了看Akka相关的知识.这篇文章主要记录了如果使用Akka来实现 ...
- server如何调用 thrift_一文带你了解 Thrift,一个可伸缩的跨语言 RPC 框架(pinpoint 源码分析系列)...
Thrift 是什么研究分布式调用链工具pinpoint的时候,在源码里看到了Thrift相关的代码,所以来了兴趣,想研究研究这个框架.Thrift 目前是 Apache 的一个项目,但是它是由fac ...
- java rpc 框架 常用_常用的RPC架构系列---gRPC
gRPC是谷歌的一个高性能,开源的高性能 RPC 框架,gRPC面向移动和HTTP/2设计.gRPC隐藏了底层的实现细节,包括序列化(json,xml),数据传输(TCP,HTTP,UDP),反序列化 ...
- 新浪微博新兵训练营系列课程——平台RPC框架介绍
新浪微博新兵训练营系列课程--平台RPC框架介绍 课程大纲 1.RPC简介 1.1 什么是RPC 1.2 RPC与其他远程调用方式比较 2.Motan RPC框架 2.1 RPC服务框架 2.2 Mo ...
- 跨语言RPC框架Hessian、Thrift、Protocol Buffer之间的选择
为什么80%的码农都做不了架构师?>>> 总结在几者之间选择的考量: 1. 如果你不需要很多语言相互调用, 希望保持清晰的java接口代码(无任何业务不相关的接口继承和方法,属 ...
最新文章
- OpenCV图像处理常用手段
- [认证授权] 5.OIDC(OpenId Connect)身份认证授权(扩展部分)
- python 柱状图 间距_专题第18篇:Python 绘图入门
- SQL Server和MysQL中的联表更新sql示例
- OpenCV_ cv2.imshow()
- 教你如何做一次真正有价值的业务数据分析
- xugang 记录一个.NET 程序员的成长 asp.net水晶报表的一些问题
- 个人记账系统c语言,C#实现_______个人记账程序
- J2Cache SpringBoot集成(j2cache-spring-boot2-starter)
- 一文教你高效画出技术架构图
- -XX:NewRatio 命令
- Mac 安装ffmpeg 并使用ffmpeg将ts格式的文件转换成mp4
- 干货丨DolphinDB即时编译(JIT)详解
- 华为已找到安卓才“替代品”?马云马斯克激辩人工智能未来;微软说:麻将AI系统终获突破;扭亏!中兴通讯上半年净利14.71亿……...
- 智慧树python第三章答案_智慧树Python语言应用第三单元章节测试答案选修课网课慕课答案...
- python 正则表达式 sub_Python 正则表达式:sub
- 你还记得当年高考时的样子吗?
- [GIS原理] 9 数字地形分析DTA、数字地形模型DTM、数字高程模型DEM、数字地表模型DSM、不规则三角网TIN
- 高效管理时间的黄金法则
- 剑指Offer II --- 2021/9/2
热门文章
- [Python爬虫] 在Windows下安装PhantomJS和CasperJS及入门介绍(上)
- 【数据结构与算法】之深入解析“24点游戏”的求解思路与算法示例
- 2016年第七届蓝桥杯 - 省赛 - C/C++大学A组 - B. 生日蜡烛
- 404. Sum of Left Leaves 左叶子之和
- CentOS curses 中文乱码问题
- Linux 中su 与su - 的区别
- 【Linux】一步一步学Linux——dhclient命令(156)
- ubantu 16.04 mysql_Ubuntu 16.04下安装MySQL
- 消防给水及消火栓系统技术规范_2019一消备考干货《消防给水及消火栓技术规范》速收藏...
- problem k: 查找某一个数_quot;细节魔鬼quot; 二分查找