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

简介: 玩转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

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

启动服务端和客户端,进行测试:

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>

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进行编译:

然后再利用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();
        }
    }
}

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

启动测试:

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

测试:

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

测试:

6 总结

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

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

相关文章
|
3月前
|
网络协议 编译器 Go
玩转gRPC—深入概念与原理
玩转gRPC—深入概念与原理
47 0
|
7月前
|
存储 JSON Go
Go语言学习 - RPC篇:深入gRPC-Gateway-探索常用数据类型
今天,我们先迈出第一步:探索RPC服务中的数据类型。掌握常见的数据类型,灵活地运用到接口设计中,能帮助我们快速地提供优雅的接口类服务。
46 0
|
2月前
|
存储 负载均衡 API
跨语言的GRPC协议
【2月更文挑战第11天】
|
4月前
|
Cloud Native 安全 Go
Go语言与gRPC的完美结合
Go语言与gRPC的完美结合
67 0
Go语言与gRPC的完美结合
|
6月前
|
编解码 网络协议 Go
golang如何使用原生RPC及微服务简述
golang如何使用原生RPC及微服务简述
|
6月前
|
安全 网络协议 网络安全
【gRPC】来聊一聊gRPC的认证
【gRPC】来聊一聊gRPC的认证
|
7月前
|
JSON 自然语言处理 Go
Golang 微服务为什么选择使用 gRPC 作为通信协议?
Golang 微服务为什么选择使用 gRPC 作为通信协议?
48 0
|
7月前
|
传感器 Cloud Native 物联网
gRpc的四种通信方式详细介绍
gRpc的四种通信方式详细介绍
138 0
|
9月前
|
负载均衡 安全 Cloud Native
2023-5-15-gRpc框架学习
2023-5-15-gRpc框架学习
110 0
|
12月前
|
Java
聊一聊 gRPC 的四种通信模式
聊一聊 gRPC 的四种通信模式