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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM