文档章节

gRPC学习笔记

OSC_fly
 OSC_fly
发布于 07/22 11:04
字数 1441
阅读 5
收藏 0

gRPC编程流程

1. gRPC服务的定义:proto文件

proto文件用于定义需要通过gRPC生成的接口,可以理解为接口定义文档

// proto语法声明
syntax = "proto3";

// option声明,相当于Java中的package声明
option go_package = "user";
option java_package = "com.ylifegroup.protobuf";

// 枚举变量定义
enum PhoneType {
    HOME = 0;
    WORK = 1;
    OTHER = 2;
}

// message定义,相当于Java中的class
message ProtobufUser {
    int32 id = 1;               // 参数定义,int32类型参数id,1表示其为第一个参数
    string name = 2;            // 参数定义,string类型参数name,2表示其为第二个参数

        // 相当于Java中的内部类
    message Phone{
        PhoneType phoneType = 1;    // 参数定义,phoneType类型参数phoneType,1表示其为第一个成员变量
        string phoneNumber = 2;     // 参数定义,string类型成员变量phoneNumber,2表示其为第二个成员变量
    }

    repeated Phone phones = 3;  // 参数定义,Phone类型成员变量phones,3表示其为第三个成员变量
}

// message声明,相当于Java中的class声明
message AddPhoneToUserRequest{
    int32 uid = 1;                  // 成员变量定义,int32类型成员变量uid,1表示其为第一个成员变量
    PhoneType phoneType = 2;        // 成员变量定义,PhoneType类型成员变量phoneType,2表示其为第二个成员变量
    string phoneNumber = 3;         // 成员变量定义,string类型成员变量phoneNumber,3表示其为第三个成员变量
}

// message声明,相当于Java中的class声明
message AddPhoneToUserResponse{
    bool result = 1;                // 成员变量定义,bool类型成员变量result,1表示其为第一个成员变量
}

// 服务定义,PhoneService服务
service PhoneService {
    // 服务方法定义,把电话添加到指定联系人的方法,请求参数AddPhoneToUserRequest,返回值AddPhoneToUserResponse
    rpc addPhoneToUser(AddPhoneToUserRequest) returns (AddPhoneToUserResponse);
}

2. 通过构建工具生成服务基类代码-Maven或Gradle

Gradle build文件代码示例:

// 插件声明
apply plugin: 'java'                        // java插件
apply plugin: 'eclipse'                     // eclipse插件
apply plugin: 'com.google.protobuf'         // protobuf插件

repositories {
    // gradle repository配置,相当于maven中配置maven repository
    jcenter()
}

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.0'
    }
}

// 源代码集合
sourceSets {
    main {
        
        // java文件所在位置
        java{
            srcDir 'gen/main/java'
            srcDir 'gen/main/grpc'
        }
        
        // proto文件所在位置
        proto {
            srcDir 'src/main/proto'
        }
    }
}

jar {
    from {
        configurations.runtime.collect {
            it.isDirectory() ? it : zipTree(it)
        }
        
        configurations.compile.collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
    
    manifest {
        attributes 'Main-Class': 'com.ylifegroup.protobuf.server.GRpcServer'
    }
}

protobuf {
    protoc {
        artifact = "com.google.protobuf:protoc:3.1.0"
    }
    
    plugins {
        grpc {
            artifact = 'io.grpc:protoc-gen-grpc-java:1.0.3'
        }
    }
    
    generatedFilesBaseDir = "$projectDir/gen/"
        
    generateProtoTasks {
        all()*.plugins {
            grpc {}
        }
    }
}

// dependencies声明,相当于maven中的依赖声明
dependencies {
    compile 'io.grpc:grpc-netty:1.0.3'				// netty依赖
    compile 'io.grpc:grpc-protobuf:1.0.3'			// protobuf依赖
    compile 'io.grpc:grpc-stub:1.0.3'				// stub依赖
// The production code uses the SLF4J logging API at compile time
    compile 'org.slf4j:slf4j-api:1.7.21'

// Declare the dependency for your favourite test framework you want to use in your tests.
// TestNG is also supported by the Gradle Test task. Just change the
// testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add
// 'test.useTestNG()' to your build script.
    testCompile 'junit:junit:4.12'
}

eclipse {
    classpath {
        defaultOutputDir = file('build/eclipse/bin')
    }
}

clean {
    delete protobuf.generatedFilesBaseDir
}

3. 服务端开发

服务端实现类须实现通过构建工具生成的服务基类

A. 服务类的实现

PhoneServiceImp.java

package com.ylifegroup.protobuf.service;

import com.ylifegroup.protobuf.PhoneServiceGrpc;
import com.ylifegroup.protobuf.Phonebook.AddPhoneToUserRequest;
import com.ylifegroup.protobuf.Phonebook.AddPhoneToUserResponse;

import io.grpc.stub.StreamObserver;

public class PhoneServiceImp extends PhoneServiceGrpc.PhoneServiceImplBase{

    /**
     * 自定义的RPC服务方法
     *
     * @param request
     * @param responseObserver
     */
    @Override
    public void addPhoneToUser(AddPhoneToUserRequest request, StreamObserver<AddPhoneToUserResponse> responseObserver) {
        // gRPC自动生成的响应对象
        AddPhoneToUserResponse response = null;
        if(request.getPhoneNumber().length() == 11 ){
            System.out.printf("uid = %s , phone type is %s, nubmer is %s\n", request.getUid(), request.getPhoneType(), request.getPhoneNumber());
            // 构建gRPC响应
            response = AddPhoneToUserResponse.newBuilder().setResult(true).build();
        }else{
            System.out.printf("The phone nubmer %s is wrong!\n",request.getPhoneNumber());
            // 构建gRPC响应
            response = AddPhoneToUserResponse.newBuilder().setResult(false).build();
        }

        // 设置gRPC响应
        responseObserver.onNext(response);
        // 返回gRPC响应
        responseObserver.onCompleted();
    }

}

B. 服务发布

GRpcServer.java

package com.ylifegroup.protobuf.server;

import io.grpc.Server;
import io.grpc.ServerBuilder;
import java.io.IOException;
import java.util.logging.Logger;
import com.ylifegroup.protobuf.service.PhoneServiceImp;


// gRPC服务端实现代码
public class GRpcServer {
    private static final Logger logger = Logger.getLogger(GRpcServer.class.getName());

    private Server server;

    // 启动gRPC服务器,开启服务
    private void start() throws IOException {
        int port = 50051;           // 服务器端口
        server = ServerBuilder                          // 服务器构建器
                .forPort(port)                          // 指定服务器端口
                .addService(new PhoneServiceImp())      // 配置需要对外发布的服务,这里是否可以一次性发布多个服务?
                .build()                                // 构建服务器对象
                .start();                               // 启动服务器,开启服务
        logger.info("Server started, listening on " + port);
        
        // gRPC服务器关闭的回调钩子函数
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                System.err.println("*** shutting down gRPC server since JVM is shutting down");
                GRpcServer.this.stop();
                System.err.println("*** server shut down");
            }
        });
    }

    // 关闭gRPC服务器
    private void stop() {
        if (server != null) {
            server.shutdown();
        }
    }

    /**
     * Await termination on the main thread since the grpc library uses daemon threads.
     */
    private void blockUntilShutdown() throws InterruptedException {
        if (server != null) {
            server.awaitTermination();
        }
    }
    
    public static void main(String[] args) throws IOException, InterruptedException {
        final GRpcServer server = new GRpcServer();
        server.start();                 // 启动gRPC服务器,开启服务
        server.blockUntilShutdown();    // 持续等待,直到服务器被关闭
    }
}

4. 客户端开发

GRpcClient.java

package com.ylifegroup.protobuf.client;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;

import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.ylifegroup.protobuf.PhoneServiceGrpc;
import com.ylifegroup.protobuf.Phonebook.AddPhoneToUserRequest;
import com.ylifegroup.protobuf.Phonebook.AddPhoneToUserResponse;
import com.ylifegroup.protobuf.Phonebook.PhoneType;

public class GRpcClient {

    private static final Logger logger = Logger.getLogger(GRpcClient.class.getName());

    private final ManagedChannel channel;                                       // 客户端与服务端连接的通道

    private final PhoneServiceGrpc.PhoneServiceBlockingStub blockingStub;       // 客户端代理stub

    /** Construct client connecting to gRPC server at {@code host:port}. */
    // 构建信道,客户端代理,绑定远程IP,服务端口
    public GRpcClient(String host, int port) {
        ManagedChannelBuilder<?> channelBuilder = ManagedChannelBuilder.forAddress(host, port).usePlaintext(true);
        channel = channelBuilder.build();           // 信道构建
        blockingStub = PhoneServiceGrpc.newBlockingStub(channel);   // 构建客户端代理
    }

    // 等待5s, 5s后关闭客户端连接
    public void shutdown() throws InterruptedException {
        channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
    }

    /** add phone to user. */
    public void addPhoneToUser(int uid, PhoneType phoneType, String phoneNubmer) {
        logger.info("Will try to add phone to user " + uid);
        // 构建gRPC请求对象
        AddPhoneToUserRequest request = AddPhoneToUserRequest.newBuilder().setUid(uid).setPhoneType(phoneType)
                .setPhoneNumber(phoneNubmer).build();
        AddPhoneToUserResponse response;
        try {
            // 发送请求,获取响应
            response = blockingStub.addPhoneToUser(request);
        } catch (StatusRuntimeException e) {
            logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
            return;
        }

        // 获取响应结果
        logger.info("Result: " + response.getResult());
    }

    public static void main(String[] args) throws Exception {
        // 创建gRPC连接客户端,指定远程IP及端口
        GRpcClient client = new GRpcClient("localhost", 50051);
        try {
            client.addPhoneToUser(1, PhoneType.WORK, "13888888888");
        } finally {
            // 关闭客户端连接
            client.shutdown();
        }
    }
}

参考文档

gRPC简单实例及流程分析

gRPC初体验

通过实例带你学习RPC框架gRPC

grpc-java

Exception in thread main java.lang.NoClassDefFoundError: io/netty/channel/socket/nio/NioSocketChannel

gRPC 官方文档中文版 V1.0

gRPC Spring Boot Starter - SprintBoot 的 gRPC 模块

grpc-spring-boot-starter

© 著作权归作者所有

共有 人打赏支持
OSC_fly
粉丝 3
博文 33
码字总数 10176
作品 0
通州
程序员
[笔记] consul用grpc做健康检查注意点

先上个代码片段开胃 protobuf写一个Health服务: https://github.com/grpc/grpc/blob/master/doc/health-checking.md package必须写成 ... consul源代码里写死了调用grpc的health check http......

疯狂的小企鹅
04/21
0
0
mac下grpc(golang server + php client)实践

目前微服务这么流行,RPC框架也是百花齐放,本文讲述一下mac下grpc的开发环境搭建,其中server端使用golang,客户端使用php。 服务端 golang grpc安装 这里列出了一个参考,由于grpc在githu...

陈晓风
07/01
0
0
gRPC Windows编译应用

gRPC Windows编译 从github上clone出来后进行cmake的编译,参考上面的文档,需要注意的点: 必须安装所有的依赖,包括Perl,Go,YASM,Git,CMake 不要使用--recursive来递归clone,因为墙的...

水海云
06/20
0
0
通过Nginx实现gRPC服务的负载均衡 | gRPC双向数据流的交互控制系列(3)

前情提要 本系列的第一篇文章 通过一个例子介绍了go语言实现gRPC双向数据流的交互控制,第二篇文章介绍了如何通过Websocket与gRPC交互。通过这两篇文章,我们可以一窥gRPC双向数据流的开发方...

阿狸不歌
08/23
0
0
Spring Boot 使用 gRPC 轻松调用远程方法

gRPC 简介 gRPC 是一个现代开源的高性能 RPC 框架,可以在任何环境下运行。它可以有效地将数据中心内和跨数据中心的服务与可插拔支持进行负载均衡、跟踪、健康检查和认证。它也适用于分布式计...

Anoyi
04/23
0
0

没有更多内容

加载失败,请刷新页面

加载更多

IDEA中Maven打包时如何跳过测试

方法1:直接使用IDEA提供的方式 Maven命令栏的工具栏有下图中的图标,上面就写着 Skip Tests 按下图标后,如下图,test就不可用了 直接使用package命令即可。 方法2:自己编辑maven命令 进入...

karma123
32分钟前
5
0
Device eth0 does not seem to be present,delaying initialization.

场景:在进行linux 主机克隆的时候,网卡初始化一般都会有问题,最常见的“Device eth0 does not seem to be present,delaying initialization.”,从字面意思 说eth0没有固化,延迟启动。由...

hnairdb
32分钟前
7
0
国内首个区块链试验区在海南成立

据新华社报道,10月8日,海南自贸区(港)区块链试验区正式在海南生态软件园授牌设立,这也是目前为止国内第一个区块链试验区。 该试验区位于海南生态软件园,与试验区同一天成立还有2家研究...

linuxCool
44分钟前
4
0
Java日期和时间获取问题

获取年月日时分秒 Calendar cal = Calendar.getInstance();//获取年int year = cal.get(Calendar.YEAR);//获取月,范围是0-11,最后使用需+1int month = cal.get(Cal...

lanyu96
今天
15
0
Ceph学习笔记2-在Kolla-Ansible中使用Ceph后端存储

环境说明 使用Kolla-Ansible请参考《使用Kolla-Ansible在CentOS 7单节点上部署OpenStack Pike》; 部署Ceph服务请参考《Ceph学习笔记1-Mimic版本多节点部署》。 配置Ceph 以osdev用户登录: ...

LastRitter
今天
19
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部