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

embedded/2025/1/16 17:31:37/

基础教程-简单案例(快入入门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.ppmy.cn/embedded/154439.html

相关文章

辅助云运维

为客户提供运维支持&#xff0c;保障业务连续性。 文章目录 一、服务范围二、服务内容三、服务流程四、 服务交付件五、责任分工六、 完成标志 一、服务范围 覆盖范围 云产品使用咨询、问题处理、配置指导等&#xff1b; 云产品相关操作的技术指导&#xff1b; 云相关资源日常…

宝塔面板 php8.0 安装 fileinfo 拓展失败

系统&#xff1a;Albaba Cloud Linux release 3 &#xff08;OpenAnolis Editon&#xff09;即 Centos 平替 异常提示&#xff1a; cc: fatal error: ** signal terminated program cc1 compilation terminated. make: *** [Makefile:211: libmagic/apprentice.lo] Error 1搜…

内聚耦合软件工程

内聚是软件工程中用来描述一个模块内部各个元素彼此结合的紧密程度的度量指标。它对于模块的独立性和可维护性有着重要影响。 内聚的类型 内聚性可以从低到高分为以下几种类型&#xff1a; 1. 偶然内聚&#xff1a;模块内的各处理元素之间没有任何联系。这种内聚性最弱。 2…

[IGP]ospf ip frr 快速重路由技术

概念 OSPF的快速重路由&#xff08;FRR&#xff09;通常是通过使用LFA算法预先计算的备用路径来实现的。这些备用路径用于在发 生链路或节点故障时迅速切换流量&#xff0c;避免网络服务中断。LFA算法计算备份链路的基本思路&#xff1a;以可提供备份链路的邻居为根节点&#…

68_Redis数据结构-QuickList

1.QuickList介绍 虽然ZipList能够节省内存,但它要求申请的内存空间必须是连续的,当内存占用较高时,这会导致申请内存的效率变得很低。如何解决这一问题?我们可以考虑通过限制ZipList的长度和单个entry的大小来减轻对连续大块内存的需求,从而优化内存申请过程。 当需要存…

我在2025年自学网络安全(黑客)

当我们谈论网络安全时&#xff0c;我们正在讨论的是保护我们的在线空间&#xff0c;这是我们所有人的共享责任。网络安全涉及保护我们的信息&#xff0c;防止被未经授权的人访问、披露、破坏或修改。 代码解释 一、网络安全的基本概念 网络安全是一种保护&#xff1a;它涉及保护…

统计学习算法——逻辑斯谛回归

内容来自B站Up主&#xff1a;动画讲编程https://www.bilibili.com/video/BV1CR4y1L7RC、风中摇曳的小萝卜https://www.bilibili.com/video/BV17r4y137bW&#xff0c;仅为个人学习所用。 极大似然估计 几率、概率与似然 几率是指某个事件发生的可能性与不发生的可能性之比&am…

刷题记录 回溯算法-10:93. 复原 IP 地址

题目&#xff1a;93. 复原 IP 地址 有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 . 分隔。 例如&#xff1a;"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址…