zoukankan      html  css  js  c++  java
  • grpc简介

    之前介绍了Google的序列化反序列化工具protobuf。在protobuf的proto文件中除了可以定义message格式,还有一种类型时service。Google想通过service来实现rpc的功能,但是并没有在protobuf中实现,而是开放给社区这个接口可以自己实现。同时Google开源了一个官方的实现grpc来生成对应的rpc调用

    proto定义

    首先在proto文件中定义想要的service

    syntax = "proto3";
    
    option java_package = "blog.proto";
    
    message Person{
    	string my_name=1;
    }
    
    message Result{
    	string string=1;
    }
    
    service HelloService {
         rpc hello(Person) returns (Result) {}
     }
    

    官方推荐在grpc中使用proto3,上面可以看到定义了一个HelloService,其下定义了hello方法,Person是入参,Result是出参。需要注意的是入参和出参无法使用简单的数据类型不然会报 Expected message type.

    编译

    proto文件是需要经过protoc来生成对应的开发语言的源码的,在grpc中需要结合使用grpc的插件来实现proto文件中的service生成java服务端/客户端文件。这里沿用之前的gradle插件

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

    在protobuf的配置中加入grpc的插件并,运行generateProto之后就可以在src/main下看到一个新的grpc目录,这个目录中就是生成的service接口,生成的文件在客户端和服务端都需要。注意,只有service的接口/类会生成在这个目录,其他的message定义还是保持生成在原来的目录。由于grpc目录不是默认的sourceset,所以编译无法找到对应的生成的java文件,不想每次编译都手动增加目录到编译路径,可以在gradle的build文件中将grpc默认加到sourceset中

    sourceSets {
        main {
            java.srcDir 'src/main/grpc'
        }
    }
    

    Server端

    在Server端需要我们手动重写service的实现并实现Server来启动服务

    //服务端的实现继承生成的ImplBase类
    public class HelloServiceImpl extends HelloServiceGrpc.HelloServiceImplBase {
        @Override
        public void hello(blog.proto.ProtoObj.Person request,
                          io.grpc.stub.StreamObserver<blog.proto.ProtoObj.Result> responseObserver) {
            System.out.println(request.getMyName()+" calling");
            //onNext返回值
            responseObserver.onNext(ProtoObj.Result.newBuilder().setString("hello, "+request.getMyName()).build());
            //服务结束
            responseObserver.onCompleted();
        }
    }
    
    //这是一个简单的Server实现
    public class HelloServer {
        private int port;
        private Server server;
        public HelloServer(int port) throws IOException {
            this.port=port;
            //server的builder
            server=ServerBuilder.forPort(port).addService(new HelloServiceImpl()).build();
            //开始服务器
            server.start();
            System.out.println("Server started, listening on " + port );
        }
    
        private void blockUntilShutdown() throws InterruptedException {
            while(true){
                server.awaitTermination();
            }
        }
        public static void main(String[] args) throws Exception {
            //启动8080端口并block线程
            (new HelloServer(8080)).blockUntilShutdown();
        }
    }
    

    之后运行main方法,服务就启动了。

    Client端

    Client端在生成完java接口后可以构建Stub与服务器通讯

    public class HelloClient {
        public static void  main(String[] args){
            //grpc的channel
            ManagedChannel channel=ManagedChannelBuilder.forAddress("127.0.0.1", 8080).usePlaintext(true).build();
            //构建服务的stub
            HelloServiceGrpc.HelloServiceBlockingStub stub= HelloServiceGrpc.newBlockingStub(channel);
            ProtoObj.Person person=ProtoObj.Person.newBuilder().setMyName("World").build();
            //调用方法
            System.out.println(stub.hello(person).getString());
            //关闭channel,不然服务端会报错“远程主机强迫关闭了一个现有的连接。”
            channel.shutdown();
        }
    }
    

    之后运行main方法就可以看到输出hello, World

  • 相关阅读:
    2019 SDN阅读作业
    2019 SDN上机第3次作业
    SDN实验2
    SDN
    说好不肝---第五次作业
    [2020BUAA软工助教]助教每周小结(week 8)
    [2020BUAA软工助教]助教每周小结(week 7)
    [2020BUAA软工助教]助教每周小结(week 6)
    [2020BUAA软工助教]助教每周小结(week 5)
    [2020BUAA软工助教]助教每周小结(week 4)
  • 原文地址:https://www.cnblogs.com/resentment/p/6714610.html
Copyright © 2011-2022 走看看