千家信息网

RPC之gRPC的使用(Java+Nodejs)

发表于:2025-01-31 作者:千家信息网编辑
千家信息网最后更新 2025年01月31日,本文介绍在Java中使用gRPC的过程。一般来说,主要包含以下的三个步骤1)在.proto文件中定义提供的服务2)使用protocol buffer编译器编译文件3)使用gRPC API来创建服务端和
千家信息网最后更新 2025年01月31日RPC之gRPC的使用(Java+Nodejs)

本文介绍在Java中使用gRPC的过程。一般来说,主要包含以下的三个步骤
1)在.proto文件中定义提供的服务
2)使用protocol buffer编译器编译文件
3)使用gRPC API来创建服务端和客户端,并进行调用。

下载和安装需要的软件

1)Protocol Buffers
结构化数据序列化机制
https://github.com/protocolbuffers/protobuf/releases
使用示例:

protoc --java_out=./ *.proto

2)protoc-gen-grpc-java
用于生成RPC通信代码
http://jcenter.bintray.com/io/grpc/protoc-gen-grpc-java/
使用示例【使用Protobuf-Plugin机制】:

protoc --plugin=protoc-gen-grpc-java=protoc-gen-grpc-java-1.19.0-windows-x86_64.exe --grpc-java_out=./ *.proto

使用Maven构建gRPC

1)修改pmo.xml

            UTF-8        3.7.0        1.19.0                                io.grpc          grpc-netty-shaded          ${grpc.version}                          io.grpc          grpc-protobuf          ${grpc.version}                          io.grpc          grpc-stub          ${grpc.version}                                  com.google.protobuf          protobuf-java          ${protobuf.version}                                  com.google.protobuf          protobuf-java-util          ${protobuf.version}                                                                    kr.motd.maven                os-maven-plugin                1.6.1                                                        org.xolstice.maven.plugins                protobuf-maven-plugin                0.6.1                                                                                                                                                                                                                        false                    com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}                    grpc-java                    io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}                                                                                                        compile                            compile-custom                                                                                    

默认情况下,该插件会查找 src/main/proto路径下的proto文件。该在路径下的任何子文件夹都会作为proto文件中使用的包路径。

2)在src/main/proto下创建proto文件(HarLog.proto)

syntax = "proto3";option java_multiple_files = true;option java_package = "com.ultrapower.ioss.proto";option java_outer_classname = "HarLogProto";package com.ultrapower.grpc.har;message HarLogResovleRequest{    string url = 1 ;    string file_name = 2;    string file_dir = 3;    string context = 4;}message HarLogResovleResponse{    int32 code = 1 ;}service HarLogService{    rpc ResovleHarLog(HarLogResovleRequest) returns (HarLogResovleResponse);    rpc BatchResovleHarLog(HarLogResovleRequest) returns (HarLogResovleResponse);}

3)编译文件

mvn protobuf:compile 或mvn compile

在target\generated-sources\protobuf下会生成以下两个文件夹

其中java文件夹下面包含了我们定义的message,而grpc-java下存放的是服务端和客户端都要使用的service。
基于上面的proto文件,生成了两个java文件

1,HarLogServiceGrpc.java   位于grpc-java下2,HarLogProto.java等其他文件位于java下

4)服务端服务实现类代码

package com.ultrapower.ioss.proto;public class HarLogServiceImpl extends HarLogServiceGrpc.HarLogServiceImplBase {    @Override    public void resovleHarLog(com.ultrapower.ioss.proto.HarLogResovleRequest request,            io.grpc.stub.StreamObserver responseObserver) {        System.out.println(request.getUrl());        System.out.println(request.getFileName());        System.out.println(request.getFileDir());        System.out.println(request.getContext());        responseObserver.onNext(HarLogResovleResponse.newBuilder().setCode(200).build());        responseObserver.onCompleted();    }    @Override    public void batchResovleHarLog(com.ultrapower.ioss.proto.HarLogResovleRequest request,            io.grpc.stub.StreamObserver responseObserver) {        responseObserver.onNext(HarLogResovleResponse.newBuilder().setCode(200).build());        responseObserver.onCompleted();    }}

5)服务端启动类

package com.ultrapower.ioss.proto;import java.io.IOException;import io.grpc.Server;import io.grpc.ServerBuilder;public class RpcServerApp {    private Server server;    private int port = 50051;    public void start() throws IOException {        server = ServerBuilder.forPort(port)                .addService(new HarLogServiceImpl())                .build()                .start();        Runtime.getRuntime().addShutdownHook(new Thread() {            @Override            public void run() {                RpcServerApp.this.stop();            }        });    }    private void stop() {        if (server != null) {            server.shutdown();        }    }    private void blockUntilShutdown() throws InterruptedException {        if (server != null) {            server.awaitTermination();        }    }    public static void main(String[] args) throws Exception {        final RpcServerApp server = new RpcServerApp();        server.start();        server.blockUntilShutdown();    }}

Nodejs端客户端

1)添加依赖

cnpm install --save grpc-toolscnpm install --save google-protobuf cnpm install --save grpccnpm install --save @grpc/proto-loadercnpm install --save @grpc/grpc-js

2)客户端代码

var grpc = require('grpc');var PROTO_PATH = __dirname + '/../grpc/protos/HarLog.proto';var protoLoader = require('@grpc/proto-loader');var packageDefinition = protoLoader.loadSync(    PROTO_PATH,    {keepCase: true,     longs: String,     enums: String,     defaults: true,     oneofs: true    });var protoDescriptor = grpc.loadPackageDefinition(packageDefinition);//protoDescriptor + "文件中定义的package"var harlog = protoDescriptor.com.ultrapower.grpc.har;/*    创建RPC客户端*/function getGrpcClient(){    //创建客户端    let client = new harlog.HarLogService('localhost:50051',grpc.credentials.createInsecure());    return client ; }/*    请求JAVA端解析生成的某个HAR文件*/function resovleHarLog(request){    let client = getGrpcClient() ;    //请求数据    /*    let request = {            url:'',            file_name:'',            file_dir:'',            context:''    } ;    */    client.resovleHarLog(request,function(error,response){        //console.log('Greeting:', response.code);        console.log('Greeting:', JSON.stringify(response));    })}/*    请求JAVA端解析指定目录下所有的HAR文件    @param dirPath 存放HAR文件的目录路径*/function batchResovleHarlog(request){    let client = getGrpcClient() ;    client.batchResovleHarLog(request,function(error,response){        console.log('Greeting:', response.message);    })}//测试resovleHarLog({            url:'www.baidu.com',            file_name:'bai.jar',            file_dir:'c://d',            context:'dsfdfdsd'    } ) ;exports.resovleHarLog = resovleHarLog;exports.batchResovleHarlog = batchResovleHarlog;

基于Java的客户端

package com.ultrapower.ioss.proto;import java.util.concurrent.TimeUnit;import io.grpc.ManagedChannel;import io.grpc.netty.shaded.io.grpc.netty.NegotiationType;import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;public class Client {    private final ManagedChannel channel;    private final HarLogServiceGrpc.HarLogServiceBlockingStub blockingStub;    /**     * 创建服务端连接,并创建"桩"     */    public Client(String host, int port) {        channel = NettyChannelBuilder.forAddress(host, port).negotiationType(NegotiationType.PLAINTEXT).build();        blockingStub = HarLogServiceGrpc.newBlockingStub(channel);    }    public void shutdown() throws InterruptedException {        channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);    }    /**     * 向服务端发送请求     */    public void resovleHarLog() {        try {            HarLogResovleRequest request = HarLogResovleRequest.newBuilder().setUrl("www.baidu.com").setFileName("test")                    .build();            HarLogResovleResponse response = blockingStub.resovleHarLog(request);            System.out.println("result from server: " + response.getCode());        } catch (RuntimeException e) {            System.out.println("RPC failed:" + e.getMessage());            return;        }    }    public static void main(String[] args) throws Exception {        Client client = new Client("127.0.0.1", 50051);        try {            client.resovleHarLog();        } finally {            client.shutdown();        }    }}

基于Nodejs的服务端

var grpc = require('grpc');var PROTO_PATH = __dirname + '/../grpc/protos/HarLog.proto';var protoLoader = require('@grpc/proto-loader');var packageDefinition = protoLoader.loadSync(    PROTO_PATH,    {keepCase: true,     longs: String,     enums: String,     defaults: true,     oneofs: true    });var protoDescriptor = grpc.loadPackageDefinition(packageDefinition);//protoDescriptor + "文件中定义的package"var harlog = protoDescriptor.com.ultrapower.grpc.har;/*    远程调用的resovleHarLog方法.    @param call 请求, 通过call.request可以得到请求参数    @param callback,调用完成后返回给调用端的结果*/function resovleHarLog(call, callback) {    let req = call.request ;    console.log(JSON.stringify(req)) ;  //callback(null, {message: 'Hello ' + call.request.name});  callback(null, {code: 300});}function batchResovleHarLog(call, callback) {    let req = call.request ;    console.log(JSON.stringify(req)) ;  //callback(null, {message: 'Hello again, ' + call.request.name});  callback(null, {code: 300});}/*    创建并启动服务端*/function startup() {  var server = new grpc.Server();  server.addProtoService(harlog.HarLogService.service,                         {resovleHarLog: resovleHarLog, batchResovleHarLog: batchResovleHarLog});  server.bind('0.0.0.0:50052', grpc.ServerCredentials.createInsecure());  server.start();}//启动服务startup() ;exports.startup = startup;
0