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

  1. cd /usr/local/src
  2. wget http://protobuf.googlecode.com/files/protobuf-2.4.1.tar.bz2
  3. tar jxvf protobuf-2.4.1.tar.bz2
  4. cd protobuf-2.4.1
  5. ./configure
  6. make
  7. make check
  8. make install

  下面将编译生成jar包,以便在java中使用Protocol Buffers,需确保已安装了maven。

  1. cd java
  2. mvn test
  3. mvn install
  4. mvn package

  安装、编译后在target/目录下会生成protobuf-java-2.4.1.jar。

2.消息结构与服务接口

  首先需要编写一个.proto文件,结构化数据被称为Message。

  1. package protobuf;
  2. option java_package = "protobuf";
  3. option java_outer_classname = "PersonProtos";
  4. option java_generic_services = true;
  5. message Person {
  6. required string name = 1;
  7. required int32 id = 2;
  8. optional string email = 3;
  9. enum PhoneType {
  10. MOBILE = 0;
  11. HOME = 1;
  12. WORK = 2;
  13. }
  14. message PhoneNumber {
  15. required string number = 1;
  16. optional PhoneType type = 2 [default = HOME];
  17. }
  18. repeated PhoneNumber phone = 4;
  19. service PhoneService {
  20. rpc GetPhone (Phone) returns (Phone);
  21. }
  22. }

  消息的成员需要指定其规则:

    (1) required:这个域在消息中必须刚好有1个;

    (2) optional:这个域在消息中可以有0或1个;

    (3) repeated:这个域在消息中可以有从多个,包括0个。

  Protobuf的类型与Java类型的映射关系:

  1. double   ->  double
  2. float    ->  float
  3. int32    ->  int
  4. int64    ->  long
  5. uint32   ->  int[1]
  6. uint64   ->  long[1]
  7. sint32   ->  int
  8. sint64   ->  long
  9. fixed32  ->  int[1]
  10. fixed64  ->  long[1]
  11. sfixed32 ->  int
  12. sfixed64 ->  long
  13. bool     ->  boolean
  14. string   ->  String
  15. bytes    ->  ByteString

  编写完.proto文件后,就可以使用下面的命令将会在protobuf目录中生成源文件PersonProtos.java

  1. protoc –java_out=. person.proto

3.序列化

  先看下面一个例子:

  1. message Test1 {
  2. required int32 a = 1;
  3. }

  创建一个Test1消息,并且把a设置为150,那么序列化后有如下3个字节:

  1. 08 96 01

3.1.varint编码

  varint编码的序列化使用一个或多个字节,数字越大使用的字节数越多。对于序列化后的字节,除了最后一个字节,都有一个most significant bit(msb):表示后边是否有更多的字节。整数序列化时按7位一组,每个字节的低7位保存一组,第一个字节存储最低位一组,即使用little endian。

  比如300序列化后的字节序列是:

  1. 10101100 00000010

  先去掉每个字节的msb:

  1. 0101100 0000010

  交换字节的顺序:

  1. 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编码

  1. message Test2 {
  2. required string b = 2;
  3. }

  将b的值设置为“testing”,编码结果为:

  1. 12 07 74 65 73 74 69 6e 67

  这里的key是0×12:field_number = 2, type = 2。字符串的长度是7。

3.5.嵌套消息

  1. message Tes3 {
  2. required Test1 c = 3;
  3. }

  c的成员a的值设置为150,编码结果为:

  1. 1a 03 08 96 01

  后三个字节和Test1一样,之前的数字3表示长度。

3.5.Repeated域

  1. message Test4 {
  2. repeated int32 d = 4;
  3. }

  {3, 270, 86942}编码结果为:

  1. 22        // tag (field number 4, wire type 2)
  2. 06        // payload size (6 bytes)
  3. 03        // first element (varint 3)
  4. 8E 02     // second element (varint 270)
  5. 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:

  1. packageprotobuf;
  2. importcom.google.protobuf.RpcController;
  3. importcom.google.protobuf.ServiceException;
  4. importprotobuf.MessageProtos.Message;
  5. importprotobuf.MessageProtos.MessageService.BlockingInterface;
  6. publicclassMessageServiceImplimplementsBlockingInterface{
  7. @Override
  8. publicMessagegetMessage(RpcControllercontroller,Messagerequest)
  9. throwsServiceException{
  10. // process request
  11.     ……
  12. returnrequest;
  13. }
  14. }

  服务端实现Server.java:

  1. packageprotobuf;
  2. importjava.util.concurrent.Executors;
  3. importcom.googlecode.protobuf.socketrpc.RpcServer;
  4. importcom.googlecode.protobuf.socketrpc.ServerRpcConnectionFactory;
  5. importcom.googlecode.protobuf.socketrpc.SocketRpcConnectionFactories;
  6. importprotobuf.MessageProtos.MessageService;
  7. publicclassServer{
  8. privateintport;
  9. privateintthreadPoolSize;
  10. publicServer(intport,intthreadPoolSize){
  11. this.port=port;
  12. this.threadPoolSize=threadPoolSize;
  13. }
  14. publicvoidrun(){
  15. // Start server
  16. ServerRpcConnectionFactoryrpcConnectionFactory=SocketRpcConnectionFactories
  17. .createServerRpcConnectionFactory(port);
  18. RpcServerserver=newRpcServer(rpcConnectionFactory,
  19. Executors.newFixedThreadPool(threadPoolSize),true);
  20. server.registerBlockingService(MessageService
  21. .newReflectiveBlockingService(newMessageServiceImpl()));
  22. server.run();
  23. }
  24. publicstaticvoidmain(String[]args){
  25. if(args.length!=2){
  26. System.out.println("Usage: Server port thread_pool_size");
  27. return;
  28. }
  29. intport=Integer.parseInt(args[0]);
  30. intsize=Integer.parseInt(args[1]);
  31. newServer(port,size).run();
  32. }
  33. }

  客户端实现Client.java:

  1. packageprotobuf;
  2. importprotobuf.MessageProtos.Message;
  3. importprotobuf.MessageProtos.MessageService;
  4. importprotobuf.MessageProtos.MessageService.BlockingInterface;
  5. importcom.google.protobuf.BlockingRpcChannel;
  6. importcom.google.protobuf.ByteString;
  7. importcom.google.protobuf.RpcController;
  8. importcom.google.protobuf.ServiceException;
  9. importcom.googlecode.protobuf.socketrpc.RpcChannels;
  10. importcom.googlecode.protobuf.socketrpc.RpcConnectionFactory;
  11. importcom.googlecode.protobuf.socketrpc.SocketRpcConnectionFactories;
  12. importcom.googlecode.protobuf.socketrpc.SocketRpcController;
  13. publicclassClient{
  14. privateintport;
  15. privateStringhost;
  16. privateintsize;
  17. privateintcount;
  18. publicClient(intport,Stringhost,intsize,intcount){
  19. super();
  20. this.port=port;
  21. this.host=host;
  22. this.size=size;
  23. this.count=count;
  24. }
  25. publiclongrun(){
  26. // Create channel
  27. RpcConnectionFactoryconnectionFactory=SocketRpcConnectionFactories
  28. .createRpcConnectionFactory(host,port);
  29. BlockingRpcChannelchannel=RpcChannels
  30. .newBlockingRpcChannel(connectionFactory);
  31. // Call service
  32. BlockingInterfaceservice=MessageService.newBlockingStub(channel);
  33. RpcControllercontroller=newSocketRpcController();
  34. Message.Buildermessage=Message.newBuilder();
  35. // initiate the message
  36. longstart=0;
  37. longend=0;
  38. try{
  39. start=System.currentTimeMillis();
  40. for(inti=0;i<count;i++){
  41. service.getMessage(controller,message.build());
  42. }
  43. end=System.currentTimeMillis();
  44. System.out.println(end-start);
  45. }catch(ServiceExceptione){
  46. e.printStackTrace();
  47. }
  48. // Check success
  49. if(controller.failed()){
  50. System.err.println(String.format("Rpc failed %s : %s",
  51. ((SocketRpcController)controller).errorReason(),
  52. controller.errorText()));
  53. }
  54. returnend-start;
  55. }
  56. publicstaticvoidmain(String[]args){
  57. if(args.length!=4){
  58. System.out.println("Usage: Client host port dataSize count");
  59. return;
  60. }
  61. Stringhost=args[0];
  62. intport=Integer.parseInt(args[1]);
  63. intsize=Integer.parseInt(args[2]);
  64. intcount=Integer.parseInt(args[3]);
  65. newClient(port,host,size,count).run();
  66. }
  67. }

5.参考资料

  (1) Protocol Buffers Documentation: http://code.google.com/apis/protocolbuffers/docs/overview.html

RPC框架系列——Protocol Buffers相关推荐

  1. RPC框架系列——Avro

    1.下载与安装 官方网站:http://avro.apache.org/ 下载地址:http://labs.renren.com/apache-mirror//avro/avro-1.5.1/avro ...

  2. RPC框架系列MessagePack

    1.下载与安装 官方网站:http://msgpack.org/ 下载地址:https://github.com/msgpack/msgpack-rpc, https://github.com/msg ...

  3. 阿里首席架构师科普RPC框架是什么

    2019独角兽企业重金招聘Python工程师标准>>> RPC概念及分类 RPC全称为Remote Procedure Call,翻译过来为"远程过程调用".目前 ...

  4. Protocol Buffers proto语言语法说明

    原文地址:http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/proto.html proto语言有自己的 数据类型(Field T ...

  5. 使用Akka实现简单RPC框架

    使用Akka实现简单RPC框架 最近简单看了看Flink的RPC通讯相关的源码,它是通过Akka实现的,为了更好的阅读理解代码,又大体看了看Akka相关的知识.这篇文章主要记录了如果使用Akka来实现 ...

  6. server如何调用 thrift_一文带你了解 Thrift,一个可伸缩的跨语言 RPC 框架(pinpoint 源码分析系列)...

    Thrift 是什么研究分布式调用链工具pinpoint的时候,在源码里看到了Thrift相关的代码,所以来了兴趣,想研究研究这个框架.Thrift 目前是 Apache 的一个项目,但是它是由fac ...

  7. java rpc 框架 常用_常用的RPC架构系列---gRPC

    gRPC是谷歌的一个高性能,开源的高性能 RPC 框架,gRPC面向移动和HTTP/2设计.gRPC隐藏了底层的实现细节,包括序列化(json,xml),数据传输(TCP,HTTP,UDP),反序列化 ...

  8. 新浪微博新兵训练营系列课程——平台RPC框架介绍

    新浪微博新兵训练营系列课程--平台RPC框架介绍 课程大纲 1.RPC简介 1.1 什么是RPC 1.2 RPC与其他远程调用方式比较 2.Motan RPC框架 2.1 RPC服务框架 2.2 Mo ...

  9. 跨语言RPC框架Hessian、Thrift、Protocol Buffer之间的选择

    为什么80%的码农都做不了架构师?>>>    总结在几者之间选择的考量: 1. 如果你不需要很多语言相互调用, 希望保持清晰的java接口代码(无任何业务不相关的接口继承和方法,属 ...

最新文章

  1. OpenCV图像处理常用手段
  2. [认证授权] 5.OIDC(OpenId Connect)身份认证授权(扩展部分)
  3. python 柱状图 间距_专题第18篇:Python 绘图入门
  4. SQL Server和MysQL中的联表更新sql示例
  5. OpenCV_ cv2.imshow()
  6. 教你如何做一次真正有价值的业务数据分析
  7. xugang 记录一个.NET 程序员的成长 asp.net水晶报表的一些问题
  8. 个人记账系统c语言,C#实现_______个人记账程序
  9. J2Cache SpringBoot集成(j2cache-spring-boot2-starter)
  10. 一文教你高效画出技术架构图
  11. -XX:NewRatio 命令
  12. Mac 安装ffmpeg 并使用ffmpeg将ts格式的文件转换成mp4
  13. 干货丨DolphinDB即时编译(JIT)详解
  14. 华为已找到安卓才“替代品”?马云马斯克激辩人工智能未来;微软说:麻将AI系统终获突破;扭亏!中兴通讯上半年净利14.71亿……...
  15. 智慧树python第三章答案_智慧树Python语言应用第三单元章节测试答案选修课网课慕课答案...
  16. python 正则表达式 sub_Python 正则表达式:sub
  17. 你还记得当年高考时的样子吗?
  18. [GIS原理] 9 数字地形分析DTA、数字地形模型DTM、数字高程模型DEM、数字地表模型DSM、不规则三角网TIN
  19. 高效管理时间的黄金法则
  20. 剑指Offer II --- 2021/9/2

热门文章

  1. [Python爬虫] 在Windows下安装PhantomJS和CasperJS及入门介绍(上)
  2. 【数据结构与算法】之深入解析“24点游戏”的求解思路与算法示例
  3. 2016年第七届蓝桥杯 - 省赛 - C/C++大学A组 - B. 生日蜡烛
  4. 404. Sum of Left Leaves 左叶子之和
  5. CentOS curses 中文乱码问题
  6. Linux 中su 与su - 的区别
  7. 【Linux】一步一步学Linux——dhclient命令(156)
  8. ubantu 16.04 mysql_Ubuntu 16.04下安装MySQL
  9. 消防给水及消火栓系统技术规范_2019一消备考干货《消防给水及消火栓技术规范》速收藏...
  10. problem k: 查找某一个数_quot;细节魔鬼quot; 二分查找