• 玩转gRPC—不同编程语言间通信


    1 简介gRPC在不同语言间是如何连接的

    在这里插入图片描述

    2 安装Protoc buffer

    下载链接:https://github.com/protocolbuffers/protobuf/releases

    Windows下建议直接下载可执行文件:
    在这里插入图片描述
    下载完成后放到指定目录,配置环境变量:
    在这里插入图片描述
    验证:
    在这里插入图片描述
    如果出现如下异常:
    在这里插入图片描述
    解决方式:

    把protoc.exe拷贝到C:\Windows\System32

    3 Go使用gRPC进行Go程序之间的通信

    项目结构:
    在这里插入图片描述
    下载依赖:

    go get google.golang.org/protobuf/runtime/protoimpl@v1.26.0
    go get google.golang.org/grpc
    go get google.golang.org/protobuf
    
    • 1
    • 2
    • 3

    go.mod文件:

    module grpc_go
    
    go 1.16
    
    require (
       google.golang.org/grpc v1.43.0 // indirect
       google.golang.org/protobuf v1.26.0 // indirect
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    protoc文件:

    syntax = "proto3";  //指定语法格式
    package proto;  //指定生成的包名字
    
    option java_package = "org.ymx.proto";
    option go_package = "/";
    
    // 定义gRPC服务接口
    service HelloService {
      // 接口的具体方法
      rpc SayHello(HelloRequest) returns (HelloReply) {}
    }
    
    // 接口的请求参数类型
    message HelloRequest {
      string name = 1;
    }
    
    // 接口的响应参数类型
    message HelloReply {
      string message = 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    到proto目录下进行编译,编译完成后会出现指定的go文件:

    C:\Users\17122\Desktop\grpc_demo\grpc_go\protoc> protoc -I . --go_out=plugins=grpc:. hello.proto
    
    • 1

    如果出现异常:

    'protoc-gen-go' 不是内部或外部命令,也不是可运行的程序 
    或批处理文件。 
    --go_out: protoc-gen-go: Plugin failed with status code 1.
    
    • 1
    • 2
    • 3

    解决方式:

    下载这个项目,到protoc-gen-go目录下,go build -o protoc-gen-go.exe main.go ,生成protoc-gen-go.exe文件

    再将protoc-gen-go.exe拷贝到C:\Windows\System32

    grpc客户端,main.go

    package main
    
    import (
       "context"
       "fmt"
       "google.golang.org/grpc"
       _ "grpc_go/proto"
       __ "grpc_go/proto"
       "log"
    )
    
    func main() {
       //1 配置grpc服务端的端口作为客户端的监听
       conn, err := grpc.Dial(":6666", grpc.WithInsecure())
       if err != nil {
          log.Fatalf("正在监听服务端 : %v\n", err)
       }
       defer conn.Close()
       //2 实例化 UserInfoService 服务的客户端
       client := __.NewHelloServiceClient(conn)
       //3 调用grpc服务
       req := new (__.HelloRequest)
       req.Name = "YMX"
       resp, err := client.SayHello(context.Background(), req)
       if err != nil {
          log.Fatalf("请求错误 : %v\n", err)
       }
       fmt.Printf("响应内容 : %v\n", resp)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    grpc服务端,main.go

    import (
       "context"
       "fmt"
       "google.golang.org/grpc"
       __ "grpc_go/proto"
       "log"
       "net"
    )
    
    //定义服务端 实现 约定的接口
    type HelloServiceServer struct{}
    
    var u = HelloServiceServer{}
    
    //实现 interface
    func (s *HelloServiceServer) SayHello(ctx context.Context, req *__.HelloRequest) (resp *__.HelloReply, err error) {
       name := req.Name
       if name == "YMX" {
          resp = &__.HelloReply{Message: "Hello YMX"}
       } else {
          resp = &__.HelloReply{Message: "Hi NoYMX"}
       }
       err = nil
       return resp, nil
    }
    
    //启动服务
    func main() {
       //1 添加监听的端口
       port := ":6666"
       l, err := net.Listen("tcp", port)
       if err != nil {
          log.Fatalf("端口监听错误 : %v\n", err)
       }
       fmt.Printf("正在监听: %s 端口\n", port)
       //2 启动grpc服务
       s := grpc.NewServer()
       //3 将UserInfoService服务注册到gRPC中,注意第二个参数是接口类型的变量,需要取地址传参
       __.RegisterHelloServiceServer(s, &u)
       s.Serve(l)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    启动服务端和客户端,进行测试:
    在这里插入图片描述

    4 Java使用gRPC进行Java程序之间的通信

    项目结构:
    在这里插入图片描述
    pom依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>org.ymx</groupId>
        <artifactId>grpc_java</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <dependencies>
            <dependency>
                <groupId>com.google.protobuf</groupId>
                <artifactId>protobuf-java</artifactId>
                <version>3.5.1</version>
            </dependency>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-all</artifactId>
                <version>1.43.0</version>
            </dependency>
        </dependencies>
    
        <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
        </properties>
        <build>
            <extensions>
                <extension>
                    <groupId>kr.motd.maven</groupId>
                    <artifactId>os-maven-plugin</artifactId>
                    <version>1.4.1.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:3.0.0:exe:${os.detected.classifier}</protocArtifact>
                        <pluginId>grpc-java</pluginId>
                        <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.0.0:exe:${os.detected.classifier}</pluginArtifact>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>compile</goal>
                                <goal>compile-custom</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    protoc文件内容:

    syntax = "proto3";  //指定语法格式
    package proto;  //指定生成的包名字;
    
    option java_multiple_files = true;
    option java_package = "org.ymx.proto";
    option go_package = "/";
    option java_outer_classname = "Hello";
    option objc_class_prefix = "YMX";
    
    
    service HelloService {
      rpc SayHello(HelloRequest) returns (HelloReply) {}
    }
    
    message HelloRequest {
      string name = 1;
    }
    
    message HelloReply {
      string message = 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    进行编译,首先利用protobuf进行编译:
    在这里插入图片描述
    然后再利用maven进行编译:
    在这里插入图片描述
    grpc服务端代码:

    package org.ymx;
    
    import io.grpc.ServerBuilder;
    import io.grpc.stub.StreamObserver;
    import org.ymx.proto.HelloReply;
    import org.ymx.proto.HelloRequest;
    import org.ymx.proto.HelloServiceGrpc;
    
    import java.io.IOException;
    
    /**
     * @desc: grpc服务端
     * @author: YanMingXin
     * @create: 2021/12/18-14:52
     **/
    public class Server {
    
        private final static int port = 5555;
        private io.grpc.Server server;
    
        private void start() throws IOException {
            server = ServerBuilder.forPort(port)
                    .addService(new HelloServiceImpl())
                    .build()
                    .start();
            System.out.println("service start...");
            Runtime.getRuntime().addShutdownHook(new Thread() {
                @Override
                public void run() {
                    System.err.println("*** shutting down gRPC server since JVM is shutting down");
                    Server.this.stop();
                    System.err.println("*** server shut down");
                }
            });
        }
    
        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 IOException, InterruptedException {
            final Server server = new Server();
            server.start();
            server.blockUntilShutdown();
        }
    
        /**
         * 实现 定义一个实现服务接口的类
         */
        private class HelloServiceImpl extends HelloServiceGrpc.HelloServiceImplBase {
    
            @Override
            public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
                System.out.println("service:" + req.getName());
                HelloReply reply = HelloReply.newBuilder().setMessage(("Hello: " + req.getName())).build();
                responseObserver.onNext(reply);
                responseObserver.onCompleted();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    grpc客户端代码:

    package org.ymx;
    
    import io.grpc.ManagedChannel;
    import io.grpc.ManagedChannelBuilder;
    import org.ymx.proto.HelloReply;
    import org.ymx.proto.HelloRequest;
    import org.ymx.proto.HelloServiceGrpc;
    
    import java.util.concurrent.TimeUnit;
    
    /**
     * @desc: grpc客户端
     * @author: YanMingXin
     * @create: 2021/12/18-14:52
     **/
    public class Client {
    
        private final ManagedChannel channel;
        private final HelloServiceGrpc.HelloServiceBlockingStub blockingStub;
    
        public Client(String host, int port) {
            channel = ManagedChannelBuilder.forAddress(host, port)
                    .usePlaintext()
                    .build();
            blockingStub = HelloServiceGrpc.newBlockingStub(channel);
        }
    
        public void shutdown() throws InterruptedException {
            channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
        }
    
        public void hello(String name) {
            HelloRequest request = HelloRequest.newBuilder().setName(name).build();
            HelloReply response = blockingStub.sayHello(request);
            System.out.println(response.getMessage());
        }
    
        public static void main(String[] args) {
            Client client = new Client("127.0.0.1", 5555);
            for (int i = 0; i < 5; i++) {
                if (i < 3) {
                    client.hello("ZS");
                } else {
                    client.hello("YMX");
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    启动测试:
    在这里插入图片描述

    5 使用gRPC进行Go和Java程序间的通信

    5.1 使用Java作为服务端,Go作为客户端

    修改客户端端口:

    Java服务端代码,其他代码不变:

    /**
     * @desc: grpc服务端
     * @author: YanMingXin
     * @create: 2021/12/18-14:52
     **/
    public class Server {
    
        private final static int port = 5555;
        private io.grpc.Server server;
    
        private void start() throws IOException {
            server = ServerBuilder.forPort(port)
                    .addService(new HelloServiceImpl())
                    .build()
                    .start();
            System.out.println("service start...");
            Runtime.getRuntime().addShutdownHook(new Thread() {
                @Override
                public void run() {
                    System.err.println("*** shutting down gRPC server since JVM is shutting down");
                    Server.this.stop();
                    System.err.println("*** server shut down");
                }
            });
        }
    
        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 IOException, InterruptedException {
            final Server server = new Server();
            server.start();
            server.blockUntilShutdown();
        }
    
        /**
         * 实现 定义一个实现服务接口的类
         */
        private class HelloServiceImpl extends HelloServiceGrpc.HelloServiceImplBase {
    
            @Override
            public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
                System.out.println("service:" + req.getName());
                HelloReply reply = HelloReply.newBuilder().setMessage(("Hello: " + req.getName())).build();
                responseObserver.onNext(reply);
                responseObserver.onCompleted();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    Go客户端代码,其他代码不变:

    import (
       "context"
       "fmt"
       "google.golang.org/grpc"
       _ "grpc_go/proto"
       __ "grpc_go/proto"
       "log"
    )
    
    func main() {
       //1 配置grpc服务端的端口作为客户端的监听
       conn, err := grpc.Dial(":5555", grpc.WithInsecure())
       if err != nil {
          log.Fatalf("正在监听服务端 : %v\n", err)
       }
       defer conn.Close()
       //2 实例化 UserInfoService 服务的客户端
       client := __.NewHelloServiceClient(conn)
       //3 调用grpc服务
       req := new (__.HelloRequest)
       req.Name = "YMX"
       resp, err := client.SayHello(context.Background(), req)
       if err != nil {
          log.Fatalf("请求错误 : %v\n", err)
       }
       fmt.Printf("响应内容 : %v\n", resp)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    测试:
    在这里插入图片描述

    5.2 使用Go作为服务端,Java作为客户端

    修改客户端端口:

    Go服务端代码,其他代码不变:

    import (
       "context"
       "fmt"
       "google.golang.org/grpc"
       __ "grpc_go/proto"
       "log"
       "net"
    )
    
    //定义服务端 实现 约定的接口
    type HelloServiceServer struct{}
    
    var u = HelloServiceServer{}
    
    //实现 interface
    func (s *HelloServiceServer) SayHello(ctx context.Context, req *__.HelloRequest) (resp *__.HelloReply, err error) {
       name := req.Name
       if name == "YMX" {
          resp = &__.HelloReply{Message: "Hello YMX"}
       } else {
          resp = &__.HelloReply{Message: "Hi NoYMX"}
       }
       err = nil
       return resp, nil
    }
    
    //启动服务
    func main() {
       //1 添加监听的端口
       port := ":6666"
       l, err := net.Listen("tcp", port)
       if err != nil {
          log.Fatalf("端口监听错误 : %v\n", err)
       }
       fmt.Printf("正在监听: %s 端口\n", port)
       //2 启动grpc服务
       s := grpc.NewServer()
       //3 将UserInfoService服务注册到gRPC中,注意第二个参数是接口类型的变量,需要取地址传参
       __.RegisterHelloServiceServer(s, &u)
       s.Serve(l)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    Java客户端代码,其他代码不变:

    /**
     * @desc: grpc客户端
     * @author: YanMingXin
     * @create: 2021/12/18-14:52
     **/
    public class Client {
    
        private final ManagedChannel channel;
        private final HelloServiceGrpc.HelloServiceBlockingStub blockingStub;
    
        public Client(String host, int port) {
            channel = ManagedChannelBuilder.forAddress(host, port)
                    .usePlaintext()
                    .build();
            blockingStub = HelloServiceGrpc.newBlockingStub(channel);
        }
    
        public void shutdown() throws InterruptedException {
            channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
        }
    
        public void hello(String name) {
            HelloRequest request = HelloRequest.newBuilder().setName(name).build();
            HelloReply response = blockingStub.sayHello(request);
            System.out.println(response.getMessage());
        }
    
        public static void main(String[] args) {
            Client client = new Client("127.0.0.1", 6666);
            for (int i = 0; i < 5; i++) {
                if (i < 3) {
                    client.hello("ZS");
                } else {
                    client.hello("YMX");
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    测试:
    在这里插入图片描述

    6 总结

    • 存放protoc的文件目录尽量用proto命名

    源码获取方式:关注下方公众号,回复【0701】

  • 相关阅读:
    数据结构:排序- 插入排序(插入排序and希尔排序) , 选择排序(选择排序and堆排序) , 交换排序(冒泡排序and快速排序) , 归并排序
    java计算机毕业设计民宿运营管理网站源码+mysql数据库+系统+lw文档+部署
    企业级java笔试题,面试题第二篇
    Redis6.2.1版本集群新加副本
    flink 运行方式和部署模式
    docker——重启策略
    “混合”引擎为通用子模块提供动力,实现嵌入式I / O灵活性
    PyQt5 | 手把手教你YOLOv5添加PyQt页面 | 3/3
    9月11日,每日信息差
    Java vo dto 使用场景
  • 原文地址:https://blog.csdn.net/Mr_YanMingXin/article/details/125551501