gRPC在Android客户端的应用

gRPC for Android

  • gRPC

    • Google 开源的 RPC(Remote Procedure Call) 框架。
    • 底层通信基于 Http2 协议。
    • 使用 ProtolBuf 作为 IDL(Interface Description Language) 和数据转换格式。
  • 环境配置:

    下载并参照 官方demo 配置。主要在 build.gradle 中配置 grpc 和 protobuf 开发环境。官方demo提供了Server端,clone之后可以直接完成通讯。

  • Client端调用:

    • 1.创建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.创建request

      添加 proto 文件之后,build生成java调用文件,
      GRPC、Request、Reply都是从这里导入并引用的。
      HelloRequest request = HelloRequest.newBuilder().build();
    • 3.创建stub,发起请求得到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()。

参考文章:GRPC原理解析

猜你喜欢

转载自blog.csdn.net/pang_gua/article/details/80022031