通过proto文件构建 完整的 gRPC 服务端和客户端案例

基础教程-简单案例(快入入门java-grpc框架)

参考官方入门案例教程:里面我看proto编译,其实直接用maven就能直接将.proto文件编译成java代码。
快速入门 | Java | gRPC 框架icon-default.png?t=O83Ahttps://grpc.org.cn/docs/languages/java/quickstart/

目录结构

src/
├── main/
│   ├── proto/
│   │   └── hello.proto                # Proto 文件
│   ├── java/
│   │   ├── com/yuan/springboot/grpc/
│   │   │   ├── HelloServiceImpl.java # 服务端实现
│   │   │   ├── GrpcServer.java       # 服务端主类
│   │   │   ├── GrpcClient.java       # 客户端实现
│   │   │   ├── MainApplication.java  # 项目入口(可选)

Step 1: 配置maven依赖


 <properties><grpc.version>1.6.1</grpc.version><protobuf.version>3.3.0</protobuf.version>
</properties>
<dependencies><dependency><groupId>io.grpc</groupId><artifactId>grpc-netty</artifactId><version>${grpc.version}</version></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-protobuf</artifactId><version>${grpc.version}</version></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-stub</artifactId><version>${grpc.version}</version></dependency><dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>${protobuf.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency></dependencies><build><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.5.0.Final</version></extension></extensions><plugins><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.5.0</version><configuration><protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin></plugins></build>

Step 2: 创建 Proto 文件

注意:

将你的 hello.proto 文件放在 src/main/proto/hello.proto 路径下。

syntax = "proto3";option java_multiple_files = true;
option java_package = "com.yuan.springboot.grpc";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";package helloworld;message HelloRequest {string name = 1;
}message HelloResponse {string message = 1;
}service HelloService {rpc sayHello(HelloRequest) returns (HelloResponse);
}

通过maven的compile直接就能编译如图:

Step 3: 实现服务端

HelloServiceImpl.java(com.yuan.springboot.grpc)

package com.yuan.springboot.grpc;import io.grpc.stub.StreamObserver;/*** @author liuyuan on 2025/1/15* 服务端实现*/
public class HelloServiceImpl extends HelloServiceGrpc.HelloServiceImplBase {@Overridepublic void sayHello(HelloRequest request, StreamObserver<HelloResponse> responseObserver) {String message = "Hello, " + request.getName() + "!";HelloResponse response = HelloResponse.newBuilder().setMessage(message).build();// 返回响应responseObserver.onNext(response);responseObserver.onCompleted();}
}
GrpcServer.java(com.yuan.springboot.grpc)
package com.yuan.springboot.grpc;import io.grpc.Server;
import io.grpc.ServerBuilder;import java.io.IOException;/*** @author liuyuan on 2025/1/15* 服务端主类*/
public class GrpcServer {public static void main(String[] args) throws IOException, InterruptedException {Server server = ServerBuilder.forPort(9090).addService(new HelloServiceImpl()).build();System.out.println("Server started on port 9090");server.start();server.awaitTermination();}}

Step 4: 实现客户端

GrpcClient.java(com.yuan.springboot.grpc)

package com.yuan.springboot.grpc;import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;/*** @author liuyuan on 2025/1/15* 客户端实现*/
public class GrpcClient {public static void main(String[] args) {// 创建 gRPC 通道ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 9090).usePlaintext(true).build();// 创建存根HelloServiceGrpc.HelloServiceBlockingStub stub = HelloServiceGrpc.newBlockingStub(channel);// 构造请求HelloRequest request = HelloRequest.newBuilder().setName("World").build();// 调用远程方法HelloResponse response = stub.sayHello(request);System.out.println("Response from server: " + response.getMessage());// 关闭通道channel.shutdown();}
}

Step 5: 启动服务端和客户端

1、在 IntelliJ IDEA 中运行 GrpcServer.java,启动服务端,如图:

2、在 IntelliJ IDEA 中运行 GrpcClient.java,启动客户端,如图:

基础教程-定义rpc方法

在服务定义中定义 rpc 方法,指定它们的请求和响应类型。gRPC 允许你定义四种服务方法

1. 简单 RPC (Simple RPC)

  • 方法名: sayHello
  • 描述: 客户端发送一个请求,服务器返回一个响应。

rpc sayHello(HelloRequest) returns (HelloResponse);

2. 服务器端流式 RPC (Server-side Streaming RPC)

  • 方法名: streamHelloResponses
  • 描述: 客户端发送一个请求,服务器返回一个流,客户端从流中读取多个响应。
rpc streamHelloResponses(HelloRequest) returns (stream HelloResponse); 

3. 客户端流式 RPC (Client-side Streaming RPC)

  • 方法名: uploadHelloRequests
  • 描述: 客户端发送一个请求流,服务器返回一个单一的响应。
rpc uploadHelloRequests(stream HelloRequest) returns (HelloResponse); 

4. 双向流式 RPC (Bidirectional Streaming RPC)

  • 方法名: chatHello
  • 描述: 客户端和服务器通过流进行双向通信,客户端和服务器可以独立发送和接收消息。
rpc chatHello(stream HelloRequest) returns (stream HelloResponse); 

四种rpc方法案例

step1 proto文件

syntax = "proto3";option java_multiple_files = true;
option java_package = "com.yuan.springboot.grpc";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";package helloworld;message HelloRequest {string name = 1;
}message HelloResponse {string message = 1;
}service HelloService {// 简单 RPCrpc sayHello(HelloRequest) returns (HelloResponse);// 服务器端流式 RPC (Server-side Streaming RPC)rpc streamHelloResponses(HelloRequest) returns (stream HelloResponse);// 客户端流式 RPC (Client-side Streaming RPC)rpc uploadHelloRequests(stream HelloRequest) returns (HelloResponse);// 双向流式 RPC (Bidirectional Streaming RPC)rpc chatHello(stream HelloRequest) returns (stream HelloResponse);}

step2 实现定义的rpc方法(服务端实现)

public class HelloServiceImpl extends HelloServiceGrpc.HelloServiceImplBase {@Overridepublic void sayHello(HelloRequest request, StreamObserver<HelloResponse> responseObserver) {String message = "Hello, " + request.getName();HelloResponse response = HelloResponse.newBuilder().setMessage(message).build();responseObserver.onNext(response);responseObserver.onCompleted();}@Overridepublic void streamHelloResponses(HelloRequest request, StreamObserver<HelloResponse> responseObserver) {String name = request.getName();for (int i = 1; i <= 5; i++) {HelloResponse response = HelloResponse.newBuilder().setMessage("Hello, " + name + "! Message " + i).build();responseObserver.onNext(response);// 模拟延迟try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}responseObserver.onCompleted();}@Overridepublic StreamObserver<HelloRequest> uploadHelloRequests(StreamObserver<HelloResponse> responseObserver) {return new StreamObserver<HelloRequest>() {private final StringBuilder messages = new StringBuilder();@Overridepublic void onNext(HelloRequest request) {messages.append("Hello, ").append(request.getName()).append("\n");}@Overridepublic void onError(Throwable t) {t.printStackTrace();}@Overridepublic void onCompleted() {HelloResponse response = HelloResponse.newBuilder().setMessage(messages.toString()).build();responseObserver.onNext(response);responseObserver.onCompleted();}};}@Overridepublic StreamObserver<HelloRequest> chatHello(StreamObserver<HelloResponse> responseObserver) {return new StreamObserver<HelloRequest>() {@Overridepublic void onNext(HelloRequest request) {String message = "Hello, " + request.getName();HelloResponse response = HelloResponse.newBuilder().setMessage(message).build();responseObserver.onNext(response);}@Overridepublic void onError(Throwable t) {t.printStackTrace();}@Overridepublic void onCompleted() {responseObserver.onCompleted();}};}}

step3 客户端实现

public class HelloClient {private final HelloServiceGrpc.HelloServiceBlockingStub blockingStub;private final HelloServiceGrpc.HelloServiceStub asyncStub;public HelloClient(String host, int port) {// 创建 gRPC 通道ManagedChannel channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext(true) // 不使用 SSL,开发环境下推荐.build();// 创建不同类型的 stubblockingStub = HelloServiceGrpc.newBlockingStub(channel);asyncStub = HelloServiceGrpc.newStub(channel);}// 简单 RPC 示例public void simpleRpc(String name) {HelloRequest request = HelloRequest.newBuilder().setName(name).build();HelloResponse response = blockingStub.sayHello(request);System.out.println("Response from server: " + response.getMessage());}// 服务器端流式 RPC 示例public void serverStreamingRpc(String name) {HelloRequest request = HelloRequest.newBuilder().setName(name).build();asyncStub.streamHelloResponses(request, new io.grpc.stub.StreamObserver<HelloResponse>() {@Overridepublic void onNext(HelloResponse response) {System.out.println("Stream response: " + response.getMessage());}@Overridepublic void onError(Throwable t) {t.printStackTrace();}@Overridepublic void onCompleted() {System.out.println("Stream completed");}});}// 客户端流式 RPC 示例public void clientStreamingRpc() {io.grpc.stub.StreamObserver<HelloRequest> requestObserver = asyncStub.uploadHelloRequests(new io.grpc.stub.StreamObserver<HelloResponse>() {@Overridepublic void onNext(HelloResponse response) {System.out.println("Response from server: " + response.getMessage());}@Overridepublic void onError(Throwable t) {t.printStackTrace();}@Overridepublic void onCompleted() {System.out.println("Stream completed");}});requestObserver.onNext(HelloRequest.newBuilder().setName("Alice").build());requestObserver.onNext(HelloRequest.newBuilder().setName("Bob").build());requestObserver.onCompleted();}// 双向流式 RPC 示例public void bidirectionalStreamingRpc() {io.grpc.stub.StreamObserver<HelloRequest> requestObserver = asyncStub.chatHello(new io.grpc.stub.StreamObserver<HelloResponse>() {@Overridepublic void onNext(HelloResponse response) {System.out.println("Response from server: " + response.getMessage());}@Overridepublic void onError(Throwable t) {t.printStackTrace();}@Overridepublic void onCompleted() {System.out.println("Stream completed");}});requestObserver.onNext(HelloRequest.newBuilder().setName("Alice").build());requestObserver.onNext(HelloRequest.newBuilder().setName("Bob").build());requestObserver.onCompleted();}
}

step4 案例测试

public class MainTest {@Testpublic void testRpcMethod_simpleRpc(){HelloClient client = new HelloClient("localhost", 9090);// 简单 RPC 调用client.simpleRpc("Alice");}@Testpublic void testRpcMethod_serverStreamingRpc() throws InterruptedException {HelloClient client = new HelloClient("localhost", 9090);// 服务器端流式 RPC 调用client.serverStreamingRpc("Bob");TimeUnit.SECONDS.sleep(6);}@Testpublic void testRpcMethod_clientStreamingRpc() throws InterruptedException {HelloClient client = new HelloClient("localhost", 9090);// 客户端流式 RPC 调用client.clientStreamingRpc();TimeUnit.SECONDS.sleep(3);}@Testpublic void testRpcMethod_bidirectionalStreamingRpc() throws InterruptedException {HelloClient client = new HelloClient("localhost", 9090);// 双向流式 RPC 调用client.bidirectionalStreamingRpc();TimeUnit.SECONDS.sleep(3);}}

总结

以上代码示例分别实现了四种 RPC 类型:

  1. 简单 RPC:一次请求-响应。
  2. 服务器端流式 RPC:服务器返回一个流。
  3. 客户端流式 RPC:客户端发送一个流。
  4. 双向流式 RPC:客户端和服务器同时发送和接收流。

每种 RPC 类型的实现方式清晰,适用于不同的业务场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/2310.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mysql--运维篇--备份和恢复(逻辑备份,mysqldump,物理备份,热备份,温备份,冷备份,二进制文件备份和恢复等)

MySQL 提供了多种备份方式&#xff0c;每种方式适用于不同的场景和需求。根据备份的粒度、速度、恢复时间和对数据库的影响&#xff0c;可以选择合适的备份策略。主要备份方式有三大类&#xff1a;逻辑备份&#xff08;mysqldump&#xff09;&#xff0c;物理备份和二进制文件备…

如何修复Android上未安装的应用程序

在Android设备上安装应用程序通常是一个简单的过程。然而&#xff0c;“ Android上未安装应用程序”是一种常见的智能手机错误消息&#xff0c;由于一个或多个原因而经常遇到。发现由于即将出现故障而无法充分利用手机&#xff0c;这当然会非常令人沮丧&#xff0c;但幸运的是&…

干净卸载Windows的Node.js环境的方法

本文介绍在Windows电脑中&#xff0c;彻底删除Node.js环境的方法。 在之前的文章Windows系统下载、部署Node.js与npm环境的方法&#xff08;https://blog.csdn.net/zhebushibiaoshifu/article/details/144810076&#xff09;中&#xff0c;我们介绍过在Windows电脑中&#xff0…

初始Java4

目录 一.继承 1.定义&#xff1a; 2.继承的语法&#xff1a; 3.子类访问父类 4.子类构造方法 5.super与this 6.继承方法 7.final关键字 &#xff08;1&#xff09;.变量不变 &#xff08;2&#xff09;.方法不变 &#xff08;3&#xff09;.类不可继承 8.继承与组合…

算法竞赛(蓝桥杯)贪心算法1——数塔问题

题目描述 有如下所示的数塔&#xff0c;要求从底层走到顶层&#xff0c;若每一步只能走到相邻的结点&#xff0c;则经过的结点的数字之和最大是多少&#xff1f; 输入 输入数据首先包括一个整数整数 N (1≤N≤100)&#xff0c;表示数塔的高度&#xff0c;接下来用 N 行数字表示…

MATLAB学习笔记-table

1.在table中叠加table table 的每一列具有固定的数据类型。如果要让表的所有单元格都可以任意填充&#xff0c;就得让每一列都是 cell 类型&#xff0c;这样表中每个单元格都是“一个元胞”。创建时可以先构造一个 空 cell 数组&#xff08;大小为行数列数&#xff09;&#x…

RabbitMQ(三)

RabbitMQ中的各模式及其用法 工作队列模式一、生产者代码1、封装工具类2、编写代码3、发送消息效果 二、消费者代码1、编写代码2、运行效果 发布订阅模式一、生产者代码二、消费者代码1、消费者1号2、消费者2号 三、运行效果四、小结 路由模式一、生产者代码二、消费者代码1、消…

django在线考试系统

Django在线考试系统是一种基于Django框架开发的在线考试平台&#xff0c;它提供了完整的在线考试解决方案。 一、系统概述 Django在线考试系统旨在为用户提供便捷、高效的在线考试环境&#xff0c;满足教育机构、企业、个人等不同场景下的考试需求。通过该系统&#xff0c;用…

Windows部署NVM并下载多版本Node.js的方法(含删除原有Node的方法)

本文介绍在Windows电脑中&#xff0c;下载、部署NVM&#xff08;node.js version management&#xff09;环境&#xff0c;并基于其安装不同版本的Node.js的方法。 在之前的文章Windows系统下载、部署Node.js与npm环境的方法&#xff08;https://blog.csdn.net/zhebushibiaoshi…

【Rust练习】28.use and pub

练习题来自&#xff1a;https://practice-zh.course.rs/crate-module/use-pub.html 1 使用 use 可以将两个同名类型引入到当前作用域中&#xff0c;但是别忘了 as 关键字. use std::fmt::Result; use std::io::Result;fn main() {}利用as可以将重名的内容取别名&#xff1a;…

React第二十二章(useDebugValue)

useDebugValue useDebugValue 是一个专为开发者调试自定义 Hook 而设计的 React Hook。它允许你在 React 开发者工具中为自定义 Hook 添加自定义的调试值。 用法 const debugValue useDebugValue(value)参数说明 入参 value: 要在 React DevTools 中显示的值formatter?:…

一体机cell服务器更换内存步骤

一体机cell服务器更换内存步骤&#xff1a; #1、确认grdidisk状态 cellcli -e list griddisk attribute name,asmmodestatus,asmdeactivationoutcome #2、offline griddisk cellcli -e alter griddisk all inactive #3、确认全部offline后进行关机操作 shutdown -h now #4、开…

VSCode连接Github的重重困难及解决方案!

一、背景&#xff1a; 我首先在github创建了一个新的项目&#xff0c;并自动创建了readme文件其次在vscode创建项目并写了两个文件在我想将vscode的项目上传到对应的github上时&#xff0c;错误出现了 二、报错及解决方案&#xff1a; 1.解决方案&#xff1a; 需要在git上配置用…

JAVA安全—JWT攻防Swagger自动化Druid泄露

前言 依旧是Java安全的内容&#xff0c;今天主要是讲JWT这个东西&#xff0c;JWT之前讲过了&#xff0c;是Java中特有的身份校验机制&#xff0c;原理我就不再多说了&#xff0c;主要是看看它的安全问题&#xff0c;至于Swagger和Druid顺便讲一下。 Druid泄露 Druid是阿里巴…

Pytorch基础教程:从零实现手写数字分类

文章目录 1.Pytorch简介2.理解tensor2.1 一维矩阵2.2 二维矩阵2.3 三维矩阵 3.创建tensor3.1 你可以直接从一个Python列表或NumPy数组创建一个tensor&#xff1a;3.2 创建特定形状的tensor3.3 创建三维tensor3.4 使用随机数填充tensor3.5 指定tensor的数据类型 4.tensor基本运算…

CDP中的Hive3之Hive Metastore(HMS)

CDP中的Hive3之Hive Metastore&#xff08;HMS&#xff09; 1、CDP中的HMS2、HMS表的存储&#xff08;转换&#xff09;3、HWC授权 1、CDP中的HMS CDP中的Hive Metastore&#xff08;HMS&#xff09;是一种服务&#xff0c;用于在后端RDBMS&#xff08;例如MySQL或PostgreSQL&a…

C#,图论与图算法,任意一对节点之间最短距离的弗洛伊德·沃肖尔(Floyd Warshall)算法与源程序

一、弗洛伊德沃肖尔算法 Floyd-Warshall算法是图的最短路径算法。与Bellman-Ford算法或Dijkstra算法一样&#xff0c;它计算图中的最短路径。然而&#xff0c;Bellman Ford和Dijkstra都是单源最短路径算法。这意味着他们只计算来自单个源的最短路径。另一方面&#xff0c;Floy…

Android中下载 HAXM 报错 HAXM installation failed,如何解决?

AMD芯片的电脑在 Android Studio 中安装 Virtual Device 时&#xff0c;经常会出现一个 问题 Intel HAXM installation failed. To install Intel HAXM follow the instructions found at: https://github.com/intel/haxm/wiki/Installation-Instructions-on-Windows 一直提示H…

少一点If/Else - 状态模式(State Pattern)

状态模式&#xff08;State Pattern&#xff09; 状态模式&#xff08;State Pattern&#xff09;状态模式&#xff08;State Pattern&#xff09;概述状态模式&#xff08;State Pattern&#xff09;结构图状态模式&#xff08;State Pattern&#xff09;涉及的角色 talk is c…

mayavi -> python 3D可视化工具Mayavi的安装

前言 Mayavi是一个基于VTK&#xff08;Visualization Toolkit&#xff09;的科学计算和可视化工具&#xff0c;主要用于数据可视化和科学计算领域。 它提供了一系列的高级可视化工具&#xff0c;包括2D和3D图形、表面和体积渲染、流场可视化等。Mayavi可以通过Python脚本进行调…