一、gRPC简介

在介绍gRPC之前先说一下RPC(Remote Procedure Call),也叫远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。相比HTTP协议来说,它主要是基于TCP/IP协议的的,传输效率更高,能够跨语言,典型的RPC框架有RMI、Hessian、Dubbo等。想要深入了解它们之间区别的话可以看这篇博客


gRPC由 google 开发,是一款语言中立、平台中立、开源的远程过程调用(RPC)系统。具备以下特性:

  1. 基于HTTP/2,HTTP/2 提供了连接多路复用、双向流、服务器推送、请求优先级、首部压缩等机制。可以节省带宽、降低TCP链接次数、节省CPU,帮助移动设备延长电池寿命等。gRPC 的协议设计上使用了HTTP2 现有的语义,请求和响应的数据使用HTTP Body 发送,其他的控制信息则用Header 表示。
  2. IDL使用ProtoBuf ,gRPC使用ProtoBuf来定义服务,ProtoBuf是由Google开发的一种数据序列化协议(类似于XML、JSON、hessian)。ProtoBuf能够将数据进行序列化,并广泛应用在数据存储、通信协议等方面。压缩和传输效率高,语法简单,表达力强。
  3. 多语言支持(C, C++, Python, PHP, Nodejs, C#, Objective-C、Golang、Java),gRPC支持多种语言,并能够基于语言自动生成客户端和服务端功能库。目前已提供了C版本grpc、Java版本grpc-java 和 Go版本grpc-go,其它语言的版本正在积极开发中,其中,grpc支持C、C++、Node.js、Python、Ruby、Objective-C、PHP和C#等语言,grpc-java已经支持Android开发。

二、认识protocol buffers

2.1简介

protocol buffers(简称protobuf),是由google开源的,在 RPC (远程方法调用)里非常流行的二进制编解码格式,类似xml,json等。主要有以下几个优点:

  1. 性能好/效率高
  2. 代码生成机制,比如可以将proto文件编译为Java文件
  3. 支持多种编程语言
  4. 支持“向后兼容”和“向前兼容”

2.2语法

2.2.1 定义一个消息类型

syntax = "proto3";

message SearchRequest {

  required string query = 1;

  optional int32 page_number = 2;

  optional int32 result_per_page = 3;

}

第一行指定了使用proto3语法,如果没有指定,编译器会使用proto2。这个指定语法行必须是文件的非空非注释的第一个行。

SearchRequest相当于我们Java中的一个实体类,里面有三个字段分别为String 类型query,int类型page_number和int类型result_per_page。

后面的数字1,2,3是标识号,必须从1开始。这些标识符是用来在消息的二进制格式中识别各个字段的,一旦开始使用就不能够再改 变。注:[1,15]之内的标识号在编码的时候会占用一个字节。[16,2047]之内的标识号则占用2个字节。所以应该为那些频繁出现的消息元素保留 [1,15]之内的标识号

字段的第一个是修饰符,必须是required,optional,repeated其中一个。

  1. required:一个格式良好的消息一定要含有1个这种字段。表示该值是必须要设置的;
  2. optional:表示可选的,可以有值也可以没有。
  3. repeated:在一个格式良好的消息中,这种字段可以重复任意多次(包括0次)。重复的值的顺序会被保留。表示该值可以重复,相当于java中的List;

字段类型与Java类型对应关系如下图:

2.2.2 定义一个服务(service)

如果想要将消息类型用在RPC(远程方法调用)系统中,可以在.proto文件中定义一个RPC服务接口,protocol buffer编译器将会根据所选择的不同语言生成服务接口代码及存根。如,想要定义一个RPC服务并具有一个方法,该方法能够接收 SearchRequest并返回一个SearchResponse,此时可以在.proto文件中进行如下定义:

service SearchService {

  rpc Search (SearchRequest) returns (SearchResponse);

}

更多相关语法可以查看这篇博客

三、完成Hello World

项目结构如图:

3.1新建项目

新建一个maven项目grpc_demo,然后在pom文件引入grpc和代码生成插件,内容如下。

  1. <properties> 

  2. <grpc.version>1.0.3</grpc.version> 

  3. </properties> 


  4. <dependencies> 

  5. <dependency> 

  6. <groupId>io.grpc</groupId> 

  7. <artifactId>grpc-netty</artifactId> 

  8. <version>${grpc.version}</version> 

  9. </dependency> 

  10. <dependency> 

  11. <groupId>io.grpc</groupId> 

  12. <artifactId>grpc-protobuf</artifactId> 

  13. <version>${grpc.version}</version> 

  14. </dependency> 

  15. <dependency> 

  16. <groupId>io.grpc</groupId> 

  17. <artifactId>grpc-stub</artifactId> 

  18. <version>${grpc.version}</version> 

  19. </dependency> 

  20. </dependencies> 


  21. <build> 

  22. <extensions> 

  23. <extension> 

  24. <groupId>kr.motd.maven</groupId> 

  25. <artifactId>os-maven-plugin</artifactId> 

  26. <version>1.4.1.Final</version> 

  27. </extension> 

  28. </extensions> 

  29. <plugins> 

  30. <plugin> 

  31. <groupId>org.xolstice.maven.plugins</groupId> 

  32. <artifactId>protobuf-maven-plugin</artifactId> 

  33. <version>0.5.0</version> 

  34. <configuration> 

  35. <protocArtifact>com.google.protobuf:protoc:3.1.0:exe:${os.detected.classifier}</protocArtifact> 

  36. <pluginId>grpc-java</pluginId> 

  37. <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact> 

  38. </configuration> 

  39. <executions> 

  40. <execution> 

  41. <goals> 

  42. <goal>compile</goal> 

  43. <goal>compile-custom</goal> 

  44. </goals> 

  45. </execution> 

  46. </executions> 

  47. </plugin> 

  48. </plugins> 

  49. </build> 

3.2编写proto文件

syntax = "proto3";

option java_multiple_files = true;
//定义包名
option java_package = "cn.sp.helloworld";
//定义生成的类名称
option java_outer_classname = "HelloWorldProto"; option objc_class_prefix = "HLW"; package helloworld; // The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greetings message HelloReply { string message = 1; }

运行命令mvn clean compile,就可以看到编译后生成的Java文件。
控制台输出:

目录结构

将这些代码复制到src/main/java/cn/sp目录下

3.3完成HelloWorldClient和HelloWorldServer

客户端代码

  1. package cn.sp.client; 


  2. import cn.sp.GreeterGrpc; 

  3. import cn.sp.HelloReply; 

  4. import cn.sp.HelloRequest; 

  5. import io.grpc.ManagedChannel; 

  6. import io.grpc.ManagedChannelBuilder; 

  7. import io.grpc.StatusRuntimeException; 


  8. import java.util.concurrent.TimeUnit; 


  9. public class HelloWorldClient { 


  10. //一个gRPC信道 

  11. private final ManagedChannel channel; 



  12. private final GreeterGrpc.GreeterBlockingStub blockingStub;//阻塞/同步 存根 


  13. //初始化信道和存根 

  14. public HelloWorldClient(int port,String host){ 

  15. this(ManagedChannelBuilder.forAddress(host,port).usePlaintext(true)); 




  16. private HelloWorldClient(ManagedChannelBuilder<?> channelBuilder){ 

  17. channel = channelBuilder.build(); 

  18. blockingStub = GreeterGrpc.newBlockingStub(channel); 




  19. public void shutDown()throws InterruptedException{ 

  20. channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); 




  21. //客户端方法 

  22. public void greet(String name){ 

  23. HelloRequest request = HelloRequest.newBuilder().setName(name).build(); 

  24. HelloReply response; 

  25. try{ 

  26. response = blockingStub.sayHello(request); 

  27. }catch (StatusRuntimeException e){ 

  28. System.out.println("RPC调用失败:"+e.getMessage()); 

  29. return; 




  30. System.out.println("服务器返回信息:"+response.getMessage()); 




  31. public static void main(String[] args)throws Exception { 

  32. HelloWorldClient client = new HelloWorldClient(50051,"127.0.0.1"); 

  33. try { 

  34. for (int i=0;i<5;i++){ 

  35. client.greet("world:"+i); 



  36. }finally { 

  37. client.shutDown(); 










服务器端代码

  1. package cn.sp.server; 


  2. import cn.sp.GreeterGrpc; 

  3. import cn.sp.HelloReply; 

  4. import cn.sp.HelloRequest; 

  5. import io.grpc.Server; 

  6. import io.grpc.ServerBuilder; 

  7. import io.grpc.stub.StreamObserver; 


  8. public class HelloWorldServer { 



  9. private int port = 50051; 

  10. private Server server; 


  11. /** 

  12. * 启动服务 

  13. * @throws Exception 

  14. */ 

  15. private void start()throws Exception{ 

  16. server = ServerBuilder.forPort(port) 

  17. .addService(new GreeterImpl()) 

  18. .build().start(); 

  19. System.out.println("service start ...."); 

  20. Runtime.getRuntime().addShutdownHook(new Thread(){ 

  21. @Override 

  22. public void run() { 

  23. System.err.println("*** shutting down gRPC server since JVM is shutting down"); 

  24. HelloWorldServer.this.stop(); 

  25. System.err.println("*** server shut down"); 



  26. }); 




  27. private void stop(){ 

  28. if (server != null){ 

  29. server.shutdown(); 





  30. // block 一直到程序退出 

  31. private void blockUntilShutDown()throws InterruptedException{ 

  32. if (server != null){ 

  33. server.awaitTermination(); 






  34. // 定义一个实现服务接口的类 

  35. private class GreeterImpl extends GreeterGrpc.GreeterImplBase{ 


  36. public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver){ 

  37. System.out.println("收到的信息:"+req.getName()); 


  38. //这里可以放置具体业务处理代码 start 

  39. //这里可以放置具体业务处理代码 end 


  40. //构造返回 

  41. HelloReply reply = HelloReply.newBuilder().setMessage("Hello: " + req.getName()).build(); 

  42. responseObserver.onNext(reply); 

  43. responseObserver.onCompleted(); 






  44. public static void main(String[] args)throws Exception { 

  45. HelloWorldServer server = new HelloWorldServer(); 

  46. server.start(); 

  47. server.blockUntilShutDown(); 






3.4运行测试

先运行服务端的main方法,再运行客户端,可以看到服务端控制台输出信息如下:

service start ....
收到的信息:world:0
收到的信息:world:1
收到的信息:world:2
收到的信息:world:3
收到的信息:world:4

客户端控制台输出信息:

服务器返回信息:Hello: world:0
服务器返回信息:Hello: world:1
服务器返回信息:Hello: world:2
服务器返回信息:Hello: world:3
服务器返回信息:Hello: world:4

说明客户端发出的五次问候请求服务端都接收到了,并且返回了响应。

四、总结

gRPC中proto文件的编写就显得十分重要了,要多加注释相当于接口文档,目前代码调用过程看着貌似有些复杂,后面整合SpringBoot之后就很简单了,不过我还是喜欢HTTP。。。。

gRPC入门的更多相关文章

  1. grpc入门(三)

    grpc入门(三) 一.介绍 本文是关于grpc的第三篇博文,是对前两篇博文的具体代码实现,秉着个人一贯的风格,没有太多抒情和总结,直接就上代码. 文章代码参考:https://github.com/ ...

  2. Go 中的 gRPC 入门详解

    目录 Go GRPC 入门 1,安装包 2,gRPC 服务端 3,gRPC 客户端 4,编译运行 5,其它 GRPC Protobuf buffer 字段类型 字段规则 Protobuf gRPC 四 ...

  3. 微服务架构攀登之路(三)之gRPC入门

    一.gRPC入门 1. gRPC 简介 gRPC 由 google 开发,是一款语言中立.平台中立.开源的远程过程调用系统 gRPC 客户端和服务端可以在多种环境中运行和交互,例如用 java 写一个 ...

  4. ASP.NET Core gRPC 入门全家桶

    一. 说明 本全家桶现在只包含了入门级别的资料,实战资料更新中. 二.官方文档 gRPC in Asp.Net Core :官方文档 gRPC 官网:点我跳转 三.入门全家桶 正片: ASP.NET ...

  5. Go GRPC 入门(一)

    前言 微服务相关 使用 GRPC 通讯的 Golang 微服务入门 举例写一个微服务,接收网址发送请求获取返回结果返回 正文 安装工具 安装 protobuf 这是 proto 文件的编译器 点我下载 ...

  6. 跟我一起学Go系列:gRPC 入门必备

    RPC 的定义这里就不再说,看文章的同学都是成熟的开发.gRPC 是 Google 开源的高性能跨语言的 RPC 方案,该框架的作者 Louis Ryan 阐述了设计这款框架的动机,有兴趣的同学可以看 ...

  7. gRPC入门—golang实现

    1.RPC 1.1 什么是RPC RPC(Remote Procedure Call),即远程过程调用,过程就是方法,简单来说,它就是一种能够像调用本地方法一样调用远程计算机进程中的方法的技术,在这种 ...

  8. grpc 入门(一)--hello world

    一,从rpc接口的定义说起,下面给一个最简单的grpc示例--hello world 在这个rpc横行的世界里,实现一个rpc很重要的一件事就是定义一个好接口,一个好的接口定义会让你省去很多麻烦.熟悉 ...

  9. grpc 入门(二)-- 服务接口类型

    本节是继上一章节Hello world的进一步深入挖掘; 一.grpc服务接口类型 在godoc的网站上对grpc的端口类型进行了简单的介绍,总共有下面4种类型[1]: gRPC lets you d ...

  10. window下golang使用gRPC入门案例&net core客户端

    gRPC是google开源高性能分布式RPC框架,支持http/2 双向数据流传输及Protobuff,可以在任何环境下运行. 它可以有效地将数据中心内和跨数据中心的服务与可插拔支持进行负载均衡,跟踪 ...

随机推荐

  1. [洛谷U22158]策划体验(树上斜率优化)(二分最优决策)

    题目背景 OL不在,Clao又在肝少*前线,他虽然觉得这个游戏的地图很烦,但是他认为地图的难度还是太低了,习习中作为策划还不够FM,于是他自己YY了一种新的地图和新的机制: 题目描述 整个地图呈树形结 ...

  2. HDU 1114 【DP】

    题意: 给你空钱袋的质量和装满钱的钱袋的质量. 给你先行的n种货币的面值和质量. 问钱包里的钱最少是多少. 如果质量不可行,输出impossible. 思路: 完全背包. 屌丝有个地方没想通,就是如何 ...

  3. how to read openstack code: service plugin

    We have learned core plugin, service plugin and extension in last post. Now let`s review: Core Plugi ...

  4. ArcGIS10.x Engine直连提示连接超时ORA-12170 来自:http://www.iarcgis.com/?p=1004

    导语 随着Esri大力宣传直连,用户也越来越由服务连接,改为直连,当然ArcGIS Engine开发用户也不例外. 环境 Oracle数据库,ArcGIS版本不限,不过由于9版本多以服务连接,以10版 ...

  5. C++第9周(春)项目5 - 一元一次方程类

    课程首页在:http://blog.csdn.net/sxhelijian/article/details/11890759,内有完整教学方案及资源链接 [项目5]设计一元一次方程类.求形如ax+b= ...

  6. 【Mongodb教程 第一课补加课2 】MongoDB下,启动服务时,出现“服务没有响应控制功能”解决方法

    如图,如果通过下列代码,添加服务后,使用net start命令出现这样的问题时,可以参考下我的解决方法. D:\MongoDB>mongod --dbpath D:\MongoDB\Data - ...

  7. JS应用之禁止抓屏、复制、打印

    JS应用之禁止抓屏.复制.打印项目需要禁止抓屏.复制.打印的要求,复制.打印做起来可能顺手一点网上各种各样的脚本俯首皆是.但抓屏怎么禁止?PrintScreen是一个特殊的键,它是没有keyCode的 ...

  8. 如何离线分析Kafka海量业务消息?1分钟快速为您支招

    场景介绍 说起Kafka,许多使用者对它是又爱又恨.Kafka是一种分布式的.基于发布/订阅的消息系统,其极致体验让人欲罢不能,但操心的运维.复杂的安全策略.可靠性易用性的缺失等,仍需要使用者付出诸多 ...

  9. Hibernate 之 二级缓存

    在上篇文章中我们对缓存以及Hibernate的一级缓存进行了介绍,接下来的主要内容将是Hibernate的二级缓存. 二级缓存也称为进程级的缓存或SessionFactory级的缓存,二级缓存可以被所 ...

  10. What Is the Linux Lokkit Utility? https://www.lifewire.com/what-is-lokkit-2192255

    lokkit: The Lokkit utility attempts to provide firewalling for the average Linux end user. Instead o ...