后端学习 - gRPC

参考官方文档

1 什么是 RPC

  • RPC 执行流程:调用方和被调用方

1. Client 调用以本地调用方式调用服务;
2. Client Stub 接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体(桩代码是未实现的接口,此处使用动态代理);
3. Client Stub 找到服务地址,并将消息发送到服务端;
4. Server Stub 收到消息后进行解码;
5. Server Stub 根据解码结果调用本地的服务;
6. 本地服务执行并将结果返回给 Server Stub;
7. Server Stub 将返回结果打包成消息并发送至消费方;
8. Client Stub 接收到消息,并进行解码;
9. Client 得到最终结果
  • Stub (桩代码)指满足形式要求但没有实现实际功能的占位或代理代码
  • RPC 中的桩代码负责远程请求或响应
  • RPC 和 HTTP 的关系

    1. 基于 HTTP 的远程调用方案(包含了接口规范、序列化反序列化等)和 RPC 是并列的
    2. 单从 HTTP 协议来看,RPC 可以使用 HTTP 作为通信协议
      在这里插入图片描述
  • 基于 HTTP 的远程调用方案和 RPC 的相同点、不同点

    • 相同点
      1. 都可以实现远程调用(上图的顶端节点)
    • 不同点
      1. 基于 HTTP RESTful 的远程调用可读性更好
      2. RPC 可以针对场景选用不同的框架(如 Dubbo、gRPC 等),不同的通信协议(HTTP、TCP、UDP),以及不同的序列化方式(JSON、PB 等),效率更高

2 ProtocolBuffer

  • PB 是一种语言无关、平台无关、可扩展的序列化结构数据的接口描述语言(Interface Description Language, IDL),可用于通信协议、数据存储等
  • 使用 service 定义服务,使用 message 定义服务使用的类
    • service 定义的每个 rpc 方法,根据输入和返回是否为 stream 修饰,分为四种情况
  • 基本语法
syntax = "proto3"  // 语法版本

option java_package = "com.hit.demo";  // 生成桩代码的包,位于target的子目录
...

// 定义服务
service PhoneLookup {
	rpc QueryPhoneByAddress (Request) returns (Response) {}
}

message Requset {
	required string id = 1;  // required:必须传入1个参数
	optional string name = 2;  // optional:可以传入0或1个参数,如果不传入则为默认0值
	repeated string address = 3;  // repeated:可以传入0或多个参数
}

message Response {
	string id = 1;
	ResultCode result = 2 [default = SUCCESS];  // 声明默认值
	repeated int64 number = 3;
	repeated bool active = 4;
	
	enum ResultCode {
		SUCCESS = 0;
		FAIL = 1;
		UNKNOWN = 3;
	}
}

3 Demo: HelloService

1. 创建 Maven 工程,导入 gRPC 依赖,配置 PB 插件

   <?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">
   
       <properties>
           <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
           <grpc.version>1.51.1</grpc.version><!-- CURRENT_GRPC_VERSION -->
           <protobuf.version>3.21.7</protobuf.version>
           <protoc.version>3.21.7</protoc.version>
           <!-- required for jdk9 -->
           <maven.compiler.source>1.7</maven.compiler.source>
           <maven.compiler.target>1.7</maven.compiler.target>
       </properties>
   
       <dependencyManagement>
           <dependencies>
               <dependency>
                   <groupId>io.grpc</groupId>
                   <artifactId>grpc-bom</artifactId>
                   <version>${grpc.version}</version>
                   <type>pom</type>
                   <scope>import</scope>
               </dependency>
           </dependencies>
       </dependencyManagement>
   
       <dependencies>
           <dependency>
               <groupId>io.grpc</groupId>
               <artifactId>grpc-netty-shaded</artifactId>
           </dependency>
           <dependency>
               <groupId>io.grpc</groupId>
               <artifactId>grpc-protobuf</artifactId>
           </dependency>
           <dependency>
               <groupId>io.grpc</groupId>
               <artifactId>grpc-stub</artifactId>
           </dependency>
           <dependency>
               <groupId>com.google.protobuf</groupId>
               <artifactId>protobuf-java-util</artifactId>
               <version>${protobuf.version}</version>
           </dependency>
           <dependency>
               <groupId>com.google.code.gson</groupId>
               <artifactId>gson</artifactId>
               <version>2.9.0</version> <!-- prevent downgrade via protobuf-java-util -->
           </dependency>
           <dependency>
               <groupId>org.apache.tomcat</groupId>
               <artifactId>annotations-api</artifactId>
               <version>6.0.53</version>
               <scope>provided</scope> <!-- not needed at runtime -->
           </dependency>
           <dependency>
               <groupId>io.grpc</groupId>
               <artifactId>grpc-testing</artifactId>
               <scope>test</scope>
           </dependency>
           <dependency>
               <groupId>junit</groupId>
               <artifactId>junit</artifactId>
               <version>4.12</version>
               <scope>test</scope>
           </dependency>
           <dependency>
               <groupId>org.mockito</groupId>
               <artifactId>mockito-core</artifactId>
               <version>3.4.0</version>
               <scope>test</scope>
           </dependency>
       </dependencies>
   
       <build>
           <extensions>
               <extension>
                   <groupId>kr.motd.maven</groupId>
                   <artifactId>os-maven-plugin</artifactId>
                   <version>1.6.2</version>
               </extension>
           </extensions>
           <plugins>
               <plugin>
                   <groupId>org.xolstice.maven.plugins</groupId>
                   <artifactId>protobuf-maven-plugin</artifactId>
                   <version>0.6.1</version>
                   <configuration>
                       <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>
                       <pluginId>grpc-java</pluginId>
                       <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
                   </configuration>
                   <executions>
                       <execution>
                           <goals>
                               <goal>compile</goal>
                               <goal>compile-custom</goal>
                           </goals>
                       </execution>
                   </executions>
               </plugin>
           </plugins>
       </build>
   </project>

2. 定义 PB

   syntax="proto3";
   
   option java_package = "com.xuecheng.fastdfs.target.stub";  // 指定桩代码在target目录下的包
   option java_generic_services = true;
   
   service HelloService {
     rpc sayHello(HelloRequest) returns (HelloResponse) {}
   }
   
   message HelloRequest {
     int32 requestId = 1;
     string name = 2;
   }
   
   message HelloResponse {
     int32 responseId = 1;
     bool responseState = 2;
     string greeting = 3;
   }

3. 执行 Maven lifecycle compile 编译工程

  • 根据插件的配置会自动执行 protobuf compile(生成message实体类)protobuf compile-customer(生成service的实现基类)

在这里插入图片描述

4. 生成桩代码,将其复制到源代码目录下

  • PB 配置的 option java_package="com.xuecheng.fastdfs.target.stub" 指定了生成的桩代码在编译结果 target 目录下的位置(蓝框所在的包),不要和复制的目标位置(红框)处于相同的包
  • 如果相同,即设置 option java_package="com.xuecheng.fastdfs.stub" ,会在后续执行 maven compile 时出现类重复的异常(因为 HelloService.proto 和源代码都想向同一个包下写入同名 class 文件)

在这里插入图片描述

5. 实现服务器和客户端逻辑、启动类

  • 服务器的逻辑和启动类
package com.xuecheng.fastdfs.demo;

import com.xuecheng.fastdfs.stub.HelloServiceGrpc;
import com.xuecheng.fastdfs.stub.HelloServiceOuterClass;
import io.grpc.Server;
import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder;
import io.grpc.stub.StreamObserver;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

public class MyHelloServer extends HelloServiceGrpc.HelloServiceImplBase {

    @Override
    public void sayHello(HelloServiceOuterClass.HelloRequest request, StreamObserver<HelloServiceOuterClass.HelloResponse> responseObserver) {
        int requestId = request.getRequestId();
        String requestName = request.getName();
        HelloServiceOuterClass.HelloResponse response = HelloServiceOuterClass.HelloResponse.newBuilder()
                .setResponseId(requestId)
                .setResponseState(true)
                .setGreeting("Hello " + requestName + "! This greeting is from server!")
                .build();
        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }

    public static void main(String[] args) {
        // 设置服务端口号
        int port = 8899;
        Server server = NettyServerBuilder.forPort(port)
                .addService(new MyHelloServer())
                .build();
        try {
            // 启动服务
            server.start();
            System.out.println("gRPC server started, on port: " + port);
            // 设置60秒后关闭
            server.awaitTermination(60, TimeUnit.SECONDS);
            System.out.println("gRPC server terminated.");
        } catch (IOException e) {
            System.out.println("Start server exception: " + e.getMessage());
            e.printStackTrace();
        } catch (InterruptedException e) {
            System.out.println("Server interrupted: " + e.getMessage());
            e.printStackTrace();
        }
    }
}
  • 客户端的逻辑和启动类
package com.xuecheng.fastdfs.demo;

import com.xuecheng.fastdfs.stub.HelloServiceGrpc;
import com.xuecheng.fastdfs.stub.HelloServiceOuterClass;
import io.grpc.ManagedChannel;
import io.grpc.netty.shaded.io.grpc.netty.NegotiationType;
import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;

public class MyHelloClient {
    public static void main(String[] args) {
        // 指定服务的ip和端口号
        String host = "192.168.0.105";
        int port = 8899;
        // 创建客户端
        ManagedChannel channel = NettyChannelBuilder.forAddress(host, port)
                .negotiationType(NegotiationType.PLAINTEXT)
                .build();
        HelloServiceGrpc.HelloServiceBlockingStub blockingStub = HelloServiceGrpc.newBlockingStub(channel);
        // 构造请求
        HelloServiceOuterClass.HelloRequest request = HelloServiceOuterClass.HelloRequest.newBuilder()
                .setRequestId(1)
                .setName("zy")
                .build();
        // 请求服务
        HelloServiceOuterClass.HelloResponse response = blockingStub.sayHello(request);
        // 解析结果
        System.out.println("Greeting: " + response.getGreeting());
    }
}

6. 启动服务,查看运行结果

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 错误提示中提到了一个未知的标志"--go-grpc",这可能是因为你的命令中使用了错误的标志。正确的命令应该是"protoc --go-grpc_out=. --go-grpc_opt=paths=source_relative user.proto"。请注意,标志"--go-grpc_out"和"--go-grpc_opt"之间应该有一个下划线"_",而不是一个空格。另外,你还需要确保你已经安装了正确的go协议编译器插件。你可以使用以下命令重新安装插件:"$ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest"和"$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest"。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* [使用protoc编译grpc问题记录(--go_out: protoc-gen-go: plugins are not supported;)](https://blog.csdn.net/m0_57777971/article/details/127864341)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [protoc-gen-go: plugin are not supported;use ‘protoc --go-grpc_out=...‘ to generate gRPC 的问题](https://blog.csdn.net/weixin_42875684/article/details/125652895)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值