本文已参加「新人创造礼」活动,一起开启创造之路。

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

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

2 安装Protoc buffer

下载链接:github.com/protocolbuf…

Windows下主张直接下载可执行文件:

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

下载完成后放到指定目录,装备环境变量:
玩转gRPC—不同编程语言间通信

验证:
玩转gRPC—不同编程语言间通信

假如呈现如下反常:
玩转gRPC—不同编程语言间通信

解决方法:

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

3 Go运用gRPC进行Go程序之间的通讯

项目结构:

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

下载依靠:

go get google.golang.org/protobuf/runtime/protoimpl@v1.26.0
go get google.golang.org/grpc
go get google.golang.org/protobuf

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
)

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;
}

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

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

假如呈现反常:

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

解决方法:

下载这个项目,到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)
}

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)
}

发动服务端和客户端,进行测验:

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

4 Java运用gRPC进行Java程序之间的通讯

项目结构:

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

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>

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;
}

进行编译,首先利用protobuf进行编译:

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

然后再利用maven进行编译:
玩转gRPC—不同编程语言间通信

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

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");
            }
        }
    }
}

发动测验:

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

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

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)
}

测验:

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

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)
}

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");
            }
        }
    }
}

测验:

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

6 总结

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

源码获取方法:重视下方公众号,回复【0701】