Application of gRPC in Android client

gRPC for Android

  • gRPC

    • Google's open source RPC (Remote Procedure Call) framework.
    • The underlying communication is based on the Http2 protocol.
    • Use ProtocolBuf as IDL (Interface Description Language) and data conversion format.
  • Environment configuration:

    Download and refer to the official demo configuration. Mainly configure grpc and protobuf development environment in build.gradle. The official demo provides the server side, and the communication can be completed directly after clone.

  • Client call:

    • 1. Create a channel

      ManagedChannel channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext(true).build();
      代码解析:
      
      * Channel通过ip和端口注册了一个与Server端连接的通道(Connection)。
      
      * usePlaintext(),指明是否跳过协商过程。
          true: PLAINTEXT: 假设连接是 plaintext(非SSL) 而且远程端点直接支持HTTP2,不需要升级。
          false: PLAINTEXT_UPGRADE: 使用 HTTP 升级协议为 plaintext(非SSL),从 HTTP/1.1 升级到 HTTP/2
      
      * Channel提供了方法获取当前连接状态或者监听连接状态。
      
          // 获取连接状态
          channel.getState(boolean requestConnection);
      
          // 监听连接状态
          channel.notifyWhenStateChanged(channel.getState(true), new Runnable() {
          @Override
          public void run() {
                  //TODO do something when state changed.
          }
          });
      
      * 1.Channel可以复用,可以一个App只使用一个Channel来维持通信。
          可以通过 channel.isShutdown() 和 channel.isTerminated() 来判断channel是否中断并重建。
        2.理论上可以创建多个Channel,在调用时选择最优线路,使用连接池模式来提高整个通信的并发能力。
          但是连接池需要自己开发维护,gRPC暂未提供,因为它违背了Http2的设计语义。
      
      * 1.ManagedChannelBuilder.forAddress()指向 ManagedChannelProvider.provider().builderForAddress()。
        2.ManagedChannelProvider有两个实现子类:OkHttpChannelProvider 和 NettyChannelProvider。
          最终使用哪一个Provider是通过Provider.priority()方法来获取并确定。
        3.源码流程:
          Okhttp -> priority -> return (GrpcUtil.IS_RESTRICTED_APPENGINE || isAndroid()) ? 8 : 3;
          Netty  -> priority -> return 5;
        4.由上可知,在Android客户端默认使用Okhttp作为Http2的封装层(当然也可以手动选择Netty)。
          这也是为什么 build.gradle 只需要导入 grpc-okhttp,而不需要导入 grpc-netty的原因。
    • 2. Create a request

      添加 proto 文件之后,build生成java调用文件,
      GRPC、Request、Reply都是从这里导入并引用的。
      HelloRequest request = HelloRequest.newBuilder().build();
    • 3. Create a stub, initiate a request to get the response

      Stub的创建成本很低,可以在每次请求时都通过channel创建新的stub。
      也可以设置deadline来复用Stub,在每次使用时先检测deadline,再决定是否重建Stub
      • 3.1. FutureStub

        GreeterGrpc.GreeterFutureStub stub = GreeterGrpc.newFutureStub(channel);
        
        ListenableFuture<HelloReply> future = stub.sayHello(request);
        
        Futures.addCallback(future, new FutureCallback<HelloReply>() {
        
            @Override
            public void onSuccess(@Nullable HelloReply result) {}
        
            @Override
            public void onFailure(Throwable t) {}
        
        });
        代码解析:
        
        * FutureStub: 一对一(一元)的非阻塞式响应。
        
        * 可以通过addCallback()方法得到未来的执行结果。
        
        * callback源码实现简述:
            1. 在while循环里执行 future.get();
            2. 得到返回值时回调回调 onSuccess();
            3. 执行过程中抛出异常时回调 onFailure()。
      • 3.2. BlockingStub

      GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(channel);
      
      // doInBackground
      HelloReply reply = stub.sayHello(request);
      代码解析:
      
      * BlockingStub: 一对一(一元)的阻塞式响应。
      
      * 内部也是基于FutureStub实现,只是在调用时就开启了while循环。
          1. 创建feature;
          2. while(future.isDone)监听;
          3. 执行结束时,返回feture.get()。
        所以BlockingStub的调用执行需要运行在子线程。
      • 3.3. Stub

        GreeterGrpc.GreeterStub stub = GreeterGrpc.newStub(channel);
        
        stub.sayHello(request, new StreamObserver<HelloReply>() {
        
            @Override
            public void onNext(HelloReply value) {}
        
            @Override
            public void onError(Throwable t) {}
        
            @Override
              public void onCompleted() {}
        
        });
        代码解析:
        
        * Stub: 一对多(流式)的非阻塞式响应。
        
        * 通过显式传入StreamObserver实现未来消息的接收。
        
        * StreamObserver源码实现简述:
            1. 收到消息(onMessage())时,调用observer.onNext();
            2. 消息流关闭(onClose())时,判断连接状态(status.isOk());
            3. 状态正常调用observer.onCompleted(),否则调用observer.onError()。

Reference article: GRPC principle analysis

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325529108&siteId=291194637