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原理解析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章