gRPC服务搭建示例

文章介绍了如何使用Protobuf进行数据结构定义,包括请求和响应消息类型,并展示了如何通过gRPC服务接口定义进行RPC调用。接着,详细说明了如何使用protoc编译工具生成Java代码,以及处理可能的错误。文章还涵盖了实现gRPC服务端逻辑,启动服务端,以及客户端调用服务端的方法。最后,给出了服务端和客户端的运行示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前备知识

  • 了解protobuf,了解IDL(Interface Define Language)

第一步,编写Protobuf

Protobuf(Protocol buffer)是谷歌主导开发的序列化框架,相比于传统的Json、XML,它是基于流的序列化,没有可读性,但是性能高,占用空间小,非常适用于RPC系统进行网络传输。先前往protobuf官方文档学习Protobuf基本语法。

Language Guide (proto 3) | Protocol Buffers Documentation (protobuf.dev)

学习完之后开始定义我们的请求数据结构、返回数据结构、服务接口:

syntax = "proto3";

option java_multiple_files = true;
option java_package = "org.example.grpcdemo";
option java_outer_classname = "DemoProto";
option java_generic_services = true;

package demo;

message Request {
  string name = 1;
}

message Response {
  string message = 1;
}

service ExampleService {
  rpc SayHello(Request) returns (Response) {}
}

文档开头指定使用proto3语法

option java_multiple_files = true表示每个结构生成单独的Java类

option java_package = "org.example.grpcdemo"表示生成的包为org.example.grpcdemooption

java_generic_services = true表示需要生成服务的定义类

接下来就是请求体定义和响应体定义。

建议在IDEA中进行编辑,安装Protobuf的插件后可以高亮显示,还能进行语法提示、代码跳转。

第二步,根据刚刚生成的proro文件生成代码

protobuf官方有protobuf compile工具(protoc),可以把刚刚定义的数据结构生成各种语言的代码,首先是下载protoc,下载地址:点击下载

下载后运行解压,可以把bin目录加入到环境变量中以便在任何地方使用,生成代码的命令如下:

protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR --go_out=DST_DIR --ruby_out=DST_DIR --objc_out=DST_DIR --csharp_out=DST_DIR path/to/file.proto

 比如生成Java代码,则命令如下:

protoc --java_out=src/main/java src/main/resources/protobuf/example.proto

该命令在项目根目录下运行,从src/main/resources/protobuf/example.proto文件生成代码,生成的代码放到src/main/java下面。

如果你按照以上步骤生成,则你只会得到请求体和响应体代码,以及对应的序列化方法,以下代码不会被编译:

service ExampleService {
  rpc SayHello(Request) returns (Response) {}
}

要服务定义生成gRPC相应的客户端和服务端存根,你需要下载一个插件

protoc-gen-grpc-java-1.31.1-windows-x86_32.exe,其他语言语言或系统自行前往下载:gRPC语言生成插件下载

下载把该可执行文件放入某个目录中,如C:\temp\bin,然后把该目录添加到环境变量中,执行如下命令生成代码:

protoc --plugin=protoc-gen-grpc-java engine.proto --java_out=out --grpc-java_out=out

你可能会遇到如下错误:protoc-gen-grpc: The system cannot find the file specified.遇到这样的错误则把protoc-gen-grpc-java替换成绝对路径可以解决,还是在根目录下面,生成gRPC代码的命令如下:

protoc --plugin=C:\temp\bin\protoc-gen-grpc-java.exe example.proto --java_out=src/main/java --grpc-java_out=src/main/java

运行后在目录中会生成如下代码: 

其中ExampleServiceGrpc类就是服务定义的类,需要服务端自己实现具体逻辑。此时你的项目可以会一片红,需要在项目中引入gRPC和Protobuf相关依赖:

    <dependencies>
        <!-- gRPC 相关依赖-->
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty-shaded</artifactId>
            <version>1.41.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
            <version>1.41.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
            <version>1.41.0</version>
        </dependency>
        <!-- Protocol Buffers 依赖 -->
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>3.22.2</version>
        </dependency>
    </dependencies>

如果还是报红,大概率是引入的protobuf-java版本低于protoc的版本,升级版本即可。

第三步,实现服务端逻辑并启动服务端

实现服务端具体业务逻辑:

public class ServiceImpl extends ExampleServiceGrpc.ExampleServiceImplBase {
    @Override
    public void sayHello(Request request, StreamObserver<Response> responseObserver) {
        System.out.println("request from client: " + request.getName());
        Response response = Response.newBuilder()
                .setMessage("Hi client!!")
                .build();
        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }
}

方法中有一个responseObserver方法,用于向客户端发送响应体。

启动服务端:

public static void main(String[] args) throws IOException, InterruptedException {
    Server server = ServerBuilder.forPort(8888)
            .addService(new ServiceImpl())
            .build();
    server.start();
    server.awaitTermination();
}

创建一个Server并指定监听端口,向服务中添加服务实现类,然后调用start方法启动服务端。

第四步,客户端对服务端进行调用

public static void main(String[] args) {
    ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 8888).usePlaintext().build();
    ExampleServiceGrpc.ExampleServiceBlockingStub stub = ExampleServiceGrpc.newBlockingStub(channel);
    Request request = Request.newBuilder()
            .setName("Hi! gRPC Server")
            .build();
    Response response = stub.sayHello(request);
    System.out.println("received from server: " + response.getMessage());
}

创建一个通信Channel,指定服务端地址和端口号,通过ExampleServiceGrpc.newBlockingStub()方法创建一个阻塞的客户端(也可以创建非阻塞的客户端),然后就可以跟调用本地方法一样对远程服务进行调用了。

运行结果如下: 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值