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

news2025/1/16 12:19:11

基础教程-简单案例(快入入门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 {

    @Override
    public 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 {
  // 简单 RPC
  rpc 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 {

    @Override
    public void sayHello(HelloRequest request, StreamObserver<HelloResponse> responseObserver) {
        String message = "Hello, " + request.getName();
        HelloResponse response = HelloResponse.newBuilder()
                .setMessage(message)
                .build();

        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }

    @Override
    public 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();
    }

    @Override
    public StreamObserver<HelloRequest> uploadHelloRequests(StreamObserver<HelloResponse> responseObserver) {
        return new StreamObserver<HelloRequest>() {
            private final StringBuilder messages = new StringBuilder();

            @Override
            public void onNext(HelloRequest request) {
                messages.append("Hello, ").append(request.getName()).append("\n");
            }

            @Override
            public void onError(Throwable t) {
                t.printStackTrace();
            }

            @Override
            public void onCompleted() {
                HelloResponse response = HelloResponse.newBuilder()
                        .setMessage(messages.toString())
                        .build();
                responseObserver.onNext(response);
                responseObserver.onCompleted();
            }
        };
    }


    @Override
    public StreamObserver<HelloRequest> chatHello(StreamObserver<HelloResponse> responseObserver) {
        return new StreamObserver<HelloRequest>() {
            @Override
            public void onNext(HelloRequest request) {
                String message = "Hello, " + request.getName();
                HelloResponse response = HelloResponse.newBuilder()
                        .setMessage(message)
                        .build();
                responseObserver.onNext(response);
            }

            @Override
            public void onError(Throwable t) {
                t.printStackTrace();
            }

            @Override
            public 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();

        // 创建不同类型的 stub
        blockingStub = 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>() {
            @Override
            public void onNext(HelloResponse response) {
                System.out.println("Stream response: " + response.getMessage());
            }

            @Override
            public void onError(Throwable t) {
                t.printStackTrace();
            }

            @Override
            public 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>() {
                    @Override
                    public void onNext(HelloResponse response) {
                        System.out.println("Response from server: " + response.getMessage());
                    }

                    @Override
                    public void onError(Throwable t) {
                        t.printStackTrace();
                    }

                    @Override
                    public 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>() {
                    @Override
                    public void onNext(HelloResponse response) {
                        System.out.println("Response from server: " + response.getMessage());
                    }

                    @Override
                    public void onError(Throwable t) {
                        t.printStackTrace();
                    }

                    @Override
                    public 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 {


    @Test
    public void testRpcMethod_simpleRpc(){
        HelloClient client = new HelloClient("localhost", 9090);
        // 简单 RPC 调用
        client.simpleRpc("Alice");
    }

    @Test
    public void testRpcMethod_serverStreamingRpc() throws InterruptedException {
        HelloClient client = new HelloClient("localhost", 9090);
        // 服务器端流式 RPC 调用
        client.serverStreamingRpc("Bob");
        TimeUnit.SECONDS.sleep(6);
    }

    @Test
    public void testRpcMethod_clientStreamingRpc() throws InterruptedException {
        HelloClient client = new HelloClient("localhost", 9090);
        // 客户端流式 RPC 调用
        client.clientStreamingRpc();
        TimeUnit.SECONDS.sleep(3);
    }


    @Test
    public 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.coloradmin.cn/o/2277526.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UML系列之Rational Rose笔记九:组件图

一、新建组件图 二、组件图成品展示 三、工作台介绍 最主要的还是这个component组件&#xff1b; 然后还有这几个&#xff0c;正常是用不到的&#xff1b;基本的使用第四部分介绍一下&#xff1a; 四、基本使用示例 这些&#xff0c;主要是运用package还有package specifica…

K8S 节点选择器

今天我们来实验 pod 调度的 nodeName 与 nodeSelector。官网描述如下&#xff1a; 假设有如下三个节点的 K8S 集群&#xff1a; k8s31master 是控制节点 k8s31node1、k8s31node2 是工作节点 容器运行时是 containerd 一、镜像准备 1.1、镜像拉取 docker pull tomcat:8.5-jre8…

c++领域展开第十二幕——类和对象(STL简介——简单了解STL)超详细!!!!

文章目录 前言STL简介什么是STLSTL的版本STL的六大组件STL的重要性如何学习STL 总结 前言 上篇博客我们了解了初阶的模版函数&#xff0c;以及有关的一些使用方法。 今天我们来了解了解STL库的有关知识 跟我一起上车吧 STL简介 什么是STL STL&#xff1a;是C标准库的重要组成…

Onedrive精神分裂怎么办(有变更却不同步)

Onedrive有时候会分裂&#xff0c;你在本地删除文件&#xff0c;并没有同步到云端&#xff0c;但是本地却显示同步成功。 比如删掉了一个目录&#xff0c;在本地看已经删掉&#xff0c;onedrive显示已同步&#xff0c;但是别的电脑并不会同步到这个删除操作&#xff0c;在网页版…

科研绘图系列:R语言绘制微生物物种系统发育树(phylogenetic tree)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍构成要素有根树与无根树构建方法应用领域说明的问题教程加载R包数据下载导入数据数据预处理系统发育树可视化准备画图数据1. 构建基础系统发育树 `p1`2. 添加条形图 `p2`3. 添加热图…

1️⃣Java中的集合体系学习汇总(List/Map/Set 详解)

目录 01. Java中的集合体系 02. 单列集合体系​ 1. Collection系列集合的遍历方式 &#xff08;1&#xff09;迭代器遍历&#xff08;2&#xff09;增强for遍历​编辑&#xff08;3&#xff09;Lambda表达式遍历 03.List集合详解 04.Set集合详解 05.总结 Collection系列…

微信小程序:跨页面数据修改全攻略

一、引言 在微信小程序开发中&#xff0c;常常会遇到需要在不同页面之间修改数据的情况。比如在商品详情页添加商品到购物车后&#xff0c;购物车页面需要实时更新商品数量和总价&#xff1b;在用户设置页面修改了个人信息&#xff0c;首页的用户信息展示区域也需要同步更新。…

寒假第一次牛客周赛 Round 76回顾

AC数&#xff1a;2&#xff08;A、C&#xff09; B 思路&#xff1a; 等价于求&#xff1a; 数量最多的字符 #include<stdio.h> int main() {int n,num;int a[26]{0};//用于存储字母 a 到 z 的出现次数。scanf("%d",&n);char s[n];scanf("%s",s)…

【 PID 算法 】PID 算法基础

一、简介 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&#xff09;、Differential&#xff08;微分&#xff09;的缩写。也就是说&#xff0c;PID算法是结合这三种环节在一起的。粘一下百度百科中的东西吧。 顾名思义&#xff0c;…

Ubuntu打开文件夹不显示文件

1.情况介绍 使用ubuntu打开文件夹不显示文件夹里面的内容&#xff0c;而是直接打开了资源查看器。 2.解决办法 命令行安装nautilus sudo apt-get install nautilus

java.text.SimpleDateFormat (日期)

前言&#xff1a; 小编最近让流感折磨的快嘎啦&#xff0c; 呜呜呜&#xff0c;拖更了俩天&#xff0c; 从明天开始我们继续日更&#xff01;&#xff01;&#xff01;&#xff01; 我们一直都是以这样的形式&#xff0c;让新手小白轻松理解复杂晦涩的概念&#xff0c; 把Ja…

游戏市场成果及趋势

2024 年的游戏行业发展情况如何&#xff1f;这是一个既关系到开发商&#xff0c;又关系到玩家的问题&#xff0c;而市场分析师可以为我们揭晓答案。下面&#xff0c;就让我们来看看分析师给出的结论以及他们对未来趋势的预测。 玩家 自 2021 年起&#xff0c;全球平均游戏时间…

Java版-oracle数据库连接测试工具-Maven配置JDBC

一、目标: 1)数据迁移方案,原RAC,新RAC 2)关闭原RAC环境,修改新RAC环境的IP=原RAC环境的IP,优点:所有的应用端不用修改数据库连接字符串。 3)测试工具目标: 3.1 Java程序,运行后cmd窗口, 3.2 链接原RAC数据库IP,每2秒查询并显示数据; 3.3 关闭/断掉原RAC服务器,…

微信小程序实现个人中心页面

文章目录 1. 官方文档教程2. 编写静态页面3. 关于作者其它项目视频教程介绍 1. 官方文档教程 https://developers.weixin.qq.com/miniprogram/dev/framework/ 2. 编写静态页面 mine.wxml布局文件 <!--index.wxml--> <navigation-bar title"个人中心" ba…

数据结构-ArrayLIst-一起探索顺序表的底层实现

各位看官早安午安晚安呀 如果您觉得这篇文章对您有帮助的话 欢迎您一键三连&#xff0c;小编尽全力做到更好 欢迎您分享给更多人哦 大家好&#xff0c;我们今天来学习java数据结构的第一章ArrayList&#xff08;顺序表&#xff09; 1.ArrayList的概念 那小伙伴就要问了线性表到…

Unity2017 控制.abc格式的三维动画播放

首先需要导入插件Alembic&#xff0c;否则导入abc动画&#xff0c;Unity是不会识别的。 Unity2017版本及以下直接从我这儿下载&#xff1a;https://download.csdn.net/download/qq_41603955/90272382 高版本Unity&#xff0c;请移步AssetStore商店搜找。 导入abc之后&#x…

docker虚拟机平台未启用问题

在终端中输入如下代码&#xff0c;重启电脑即可 Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform 对于Docker Desktop - Unexpected WSL error问题 参考链接 解决WSL2与docker冲突问题

软件设计大致步骤

由于近期在做软件架构设计&#xff0c;这里总结下大致的设计流程 软件设计流程 1 首先要先写系统架构图&#xff0c;将该功能在整个系统的位置以及和大致的内部模块划分 2 然后写内部的结构图&#xff0c;讲内部的各个子系统&#xff0c;模块&#xff0c;组件之间的关系和调用…

EasyLine(v2.0)自制光谱、曲线处理软件

前言&#xff1a;因为这次更新对软件的整体变动较大&#xff0c;所以就没有取版本v1.1&#xff0c;而是直接使用v2.0版本。然后上一版的讲解也不是很清楚&#xff0c;这次也做重点讲解一下。 自制光谱、曲线处理软件-EasyLine 软件的安装软件的使用总体介绍文件格式处理的使用 …

赛灵思(Xilinx)公司Artix-7系列FPGA

苦难从不值得歌颂&#xff0c;在苦难中萃取的坚韧才值得珍视&#xff1b; 痛苦同样不必美化&#xff0c;从痛苦中开掘出希望才是壮举。 没有人是绝对意义的主角&#xff0c; 但每个人又都是自己生活剧本里的英雄。滑雪&#xff0c;是姿态优雅的“贴地飞行”&#xff0c;也有着成…