Android中GRPC的使用-4种通信模式

news2024/11/28 10:59:53

GRPC的通信模式

        GRPC四种基础通信模式:一元RPC、服务器端流RPC、客户端流RPC以及双向流RPC。下面分别四种模式进行介绍,并在Android环境中来实现服务和客户端。

一元RPC

        一元RPC模式也被称为简单RPC模式。在该模式中,当客户端调用服务端的远程方法时,客户端发送请求值服务端并获得一个响应,与响应一起发送的还有状态细节以及trailer元数据。客户端与服务端流程如下:

代码实现

        假设需要为基于GRPC的在线零售应用程序构建OrderManagement服务,并在该服务中定义getOrderByUnary方法。使用该方法,客户端可以通过订单ID检索已有的订单。客户端发送一个带有订单的ID的请求,服务器给出响应,响应中包含订单信息。因此,他遵循一元RPC模式。

 协议定义

        首先定义服务与消息类型,在main/proto下创建order_management.proto文件,内容如下:

syntax = "proto3";
import "google/protobuf/wrappers.proto";
package order;
service OrderManagement {
  rpc getOrderByUnary(google.protobuf.StringValue) returns (Order);

}
message Order {
  string id = 1;

}

 客户端

        创建OrderClient类作为客户端,具体代码代码实现如下:

private final String TAG = "OrderClient";
    private ManagedChannel channel;
    private OrderManagementGrpc.OrderManagementStub stub;
    public OrderClient(String ip,int port){
        channel = ManagedChannelBuilder
                .forAddress(ip, port)
                .usePlaintext()
                .build();
        stub = OrderManagementGrpc.newStub(channel); // 生成一个远端服务在client的存根,看名称应该是阻塞调用
    }

    public void getOrderByUnary(String id){
        Log.d(TAG,"getOrderByUnary start id = " + id);
        stub.getOrderByUnary(StringValue.newBuilder().setValue(id).build(), new StreamObserver<OrderManagementOuterClass.Order>() {
            @Override
            public void onNext(OrderManagementOuterClass.Order value) {
                Log.d(TAG,"getOrderByUnary onNext : id " + value.getId());
            }

            @Override
            public void onError(Throwable t) {
                Log.d(TAG,"getOrderByUnary onError: " +t.getMessage());
            }

            @Override
            public void onCompleted() {
                Log.d(TAG,"getOrderByUnary onCompleted.");
            }
        });
    }
}

服务端

        创建OrderServer类作为服务端,具体代码如下:

public class OrderServer extends OrderManagementGrpc.OrderManagementImplBase {
    private final String TAG = "OrderServer";
    private Server server;
    private int port;
    public OrderServer(int port){
        this.port = port;
    }

    public void start(){
        Log.d(TAG," start");
        try {
            server = NettyServerBuilder.forPort(port)
                    .addService(this)
                    .build()
                    .start();
        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG," start exception = " + e.getMessage());
        }
        Log.d(TAG," port = " + port);
        //等待服务关闭,这样是服务一直等待使用的状态了
        try {
            server.awaitTermination();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void getOrderByUnary(StringValue request, StreamObserver<OrderManagementOuterClass.Order> responseObserver) {
        Log.d(TAG," getOrderByUnary request = " + request.getValue());
        OrderManagementOuterClass.Order order = OrderManagementOuterClass
                .Order.newBuilder().setId(request.getValue() +"-1").build();
        responseObserver.onNext(order);
        responseObserver.onCompleted();
    }
}

 使用

        首先创建服务类,并启动服务,之后创建客户端,并调用getOrderByUnary方法,具体实现如下:

public class MainServerActivity extends AppCompatActivity {
    private final String TAG = "MainServerActivity";
    private Scheduler.Worker workerServer;
    private Scheduler.Worker workerClient;
    int port = 3452;
    private int id;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Scheduler scheduler =     
        Schedulers.from(Executors.newSingleThreadScheduledExecutor());
        workerServer = scheduler.createWorker();
        workerServer.schedule(() ->{
            startServer();
        });

        scheduler = Schedulers.from(Executors.newSingleThreadScheduledExecutor());
        workerClient = scheduler.createWorker();
        client = new OrderClient("127.0.0.1",port);
        findViewById(R.id.bt_get_order_unary).setOnClickListener(v -> {
            workerClient.schedule(() ->{
                getOrderByUnary(id++ +"");
            });
        });

      
    }

    OrderServer server;
    public void startServer(){
        server = new OrderServer(port);
        server.start();

    }

    OrderClient client;
    public void getOrderByUnary(String id){
        client.getOrderByUnary(id);

    }

}

        执行结果如下所示:

2022-12-15 15:04:50.987 30372-30503/com.reactnative.grpcserverdemo D/OrderClient: getOrderByUnary start id = 0
2022-12-15 15:04:51.550 30372-30505/com.reactnative.grpcserverdemo D/OrderServer:  getOrderByUnary request = 0
2022-12-15 15:04:51.594 30372-30505/com.reactnative.grpcserverdemo D/OrderClient: getOrderByUnary onNext : id 0-1
2022-12-15 15:04:51.598 30372-30505/com.reactnative.grpcserverdemo D/OrderClient: getOrderByUnary onCompleted.

服务器端流RPC

        在一元RPC模式中,GRPC服务器端和GRPC客户端在通信时始终只有一个请求和一个响应。在服务器端流RPC模式中,服务器端在接收到客户端请求消息后,会发回一个响应的序列。这种多个响应所组成的列表页被称为“流”。在讲所有的服务端响应发送完成之后,服务器端会以trailer元数据的形式将其状态发送给客户端,从而标记流的结束。客户端与服务端流程如下:

协议定义

        在之前定义好服务中增加getOrderByServerStream方法,具体如下:

rpc getOrderByServerStream(google.protobuf.StringValue) returns ( stream Order);

客户端

        在客户OrderClient类中增加getOrderByServerStream方法,代码如下:

public void getOrderByServerStream(String id){
        Log.d(TAG,"getOrderByServerStream start id = " + id);
        stub.getOrderByServerStream(StringValue.newBuilder().setValue(id).build(), new StreamObserver<OrderManagementOuterClass.Order>() {
            @Override
            public void onNext(OrderManagementOuterClass.Order value) {
                Log.d(TAG,"getOrderByServerStream onNext : id " + value.getId());
            }

            @Override
            public void onError(Throwable t) {
                Log.d(TAG,"getOrderByServerStream onError: " +t.getMessage());
            }

            @Override
            public void onCompleted() {
                Log.d(TAG,"getOrderByServerStream onCompleted.");
            }
        });


 }

服务端

        在服务端OrderServer类中增加getOrderByServerStream方法,具体实现如下:

    public void getOrderByServerStream(StringValue request, StreamObserver<OrderManagementOuterClass.Order> responseObserver) {
        Log.d(TAG," getOrderByServerStream request = " + request.getValue());
        OrderManagementOuterClass.Order order = OrderManagementOuterClass
                .Order.newBuilder().setId(request.getValue() +"-1").build();
        responseObserver.onNext(order);
        order = OrderManagementOuterClass
                .Order.newBuilder().setId(request.getValue() +"-2").build();
        responseObserver.onNext(order);
        responseObserver.onCompleted();
    }

使用

        之后调用getOrderByServerStream,具体实现如下:

 findViewById(R.id.bt_get_order_server_stream).setOnClickListener(v -> {
            workerClient.schedule(() ->{
                getOrderByServerStream(id++ +"");
            });
        });

 public void getOrderByServerStream(String id){
        client.getOrderByServerStream(id);

    }

          执行结果如下所示: 

2022-12-15 15:21:05.168 30372-31756/com.reactnative.grpcserverdemo D/OrderClient: getOrderByServerStream start id = 0
2022-12-15 15:21:05.265 30372-31760/com.reactnative.grpcserverdemo D/OrderServer:  getOrderByServerStream request = 0
2022-12-15 15:21:05.309 30372-31757/com.reactnative.grpcserverdemo D/OrderClient: getOrderByServerStream onNext : id 0-1
2022-12-15 15:21:05.313 30372-31757/com.reactnative.grpcserverdemo D/OrderClient: getOrderByServerStream onNext : id 0-2
2022-12-15 15:21:05.314 30372-31757/com.reactnative.grpcserverdemo D/OrderClient: getOrderByServerStream onCompleted.

        可见,服务端可以进行多次响应。 

客户端流RPC

        在客户端流RPC模式中个,客户端会发送多个请求给服务器端,而不再是单个请求。服务器端则会发送一个响应给客户端。但是服务器端不一定要等到从客户端接收到所有消息才发送响应。基于这样额逻辑,我们可以在接收到流中一个消息或几条消息之后就发送响应,也可以在读取完流中所有消息之后再发送响应。客户端与服务端流程如下:

协议定义

        在之前定义好服务中增加getOrderByClientStream方法,具体如下:

rpc getOrderByClientStream(stream google.protobuf.StringValue) returns (Order);

客户端

         在客户OrderClient类中增加getOrderByClientStream方法,代码如下:

 public void getOrderByClientStream(){
        StreamObserver<StringValue> observer = stub.getOrderByClientStream(new StreamObserver<OrderManagementOuterClass.Order>() {

            @Override
            public void onNext(OrderManagementOuterClass.Order value) {
                Log.d(TAG,"getOrderByClientStream onNext : id = " + value.getId());
            }

            @Override
            public void onError(Throwable t) {
                Log.d(TAG,"getOrderByServerStream onError: " +t.getMessage());
            }

            @Override
            public void onCompleted() {
                Log.d(TAG,"getOrderByClientStream onCompleted.");
            }
        });
        observer.onNext(StringValue.newBuilder().setValue("1").build());
        observer.onNext(StringValue.newBuilder().setValue("2").build());
        observer.onCompleted();
    }

服务端

        在服务端OrderServer类中增加getOrderByClientStream方法,具体实现如下:

 public StreamObserver<StringValue> getOrderByClientStream(StreamObserver<OrderManagementOuterClass.Order> responseObserver) {
        return new StreamObserver<StringValue>() {
            @Override
            public void onNext(StringValue value) {
                Log.d(TAG," getOrderByClientStream onNext request = " + value);
            }

            @Override
            public void onError(Throwable t) {
                Log.d(TAG," getOrderByClientStream onError = " + t.getMessage());
            }

            @Override
            public void onCompleted() {
                Log.d(TAG," getOrderByClientStream onCompleted");
                responseObserver.onNext(OrderManagementOuterClass
                        .Order.newBuilder().setId("1").build());
                responseObserver.onCompleted();
            }
        };
    }

使用

         之后调用getOrderByClientStream,具体实现如下:

 findViewById(R.id.bt_get_order_client_stream).setOnClickListener(v -> {
            workerClient.schedule(() ->{
                getOrderByClientStream();
            });
        });

 public void getOrderByClientStream(){
        client.getOrderByClientStream();
    }

          执行结果如下所示:  

2022-12-15 16:16:14.013 5112-5203/com.reactnative.grpcserverdemo D/OrderServer:  getOrderByClientStream onNext request = # com.google.protobuf.StringValue@7c694
    value: "1"
2022-12-15 16:16:14.024 5112-5203/com.reactnative.grpcserverdemo D/OrderServer:  getOrderByClientStream onNext request = # com.google.protobuf.StringValue@7c6c9
    value: "2"
2022-12-15 16:16:14.025 5112-5203/com.reactnative.grpcserverdemo D/OrderServer:  getOrderByClientStream onCompleted
2022-12-15 16:16:14.063 5112-5203/com.reactnative.grpcserverdemo D/OrderClient: getOrderByClientStream onNext : id = 1
2022-12-15 16:16:14.066 5112-5203/com.reactnative.grpcserverdemo D/OrderClient: getOrderByClientStream onCompleted.

双向流RPC

        在双向流RPC模式中,客户端已消息流的形式发送请求到服务端,服务器也以消息流的形式进行响应。调用必须有客户端发起,但在此之后,通信完全基于GRPC客户端和服务端的应用程序逻辑。客户端与服务端流程如下:

协议定义

        在之前定义好服务中增加getOrderByTwoWayStream方法,具体如下:

rpc getOrderByTwoWayStream(stream google.protobuf.StringValue) returns (stream Order);

客户端

        在客户OrderClient类中增加getOrderByTwoWayStream方法,代码如下:

 public void getOrderByTwoWayStream(){
        StreamObserver<StringValue> observer = stub.getOrderByTwoWayStream(new StreamObserver<OrderManagementOuterClass.Order>() {

            @Override
            public void onNext(OrderManagementOuterClass.Order value) {
                Log.d(TAG,"getOrderByTwoWayStream onNext : id = " + value.getId());
            }

            @Override
            public void onError(Throwable t) {
                Log.d(TAG,"getOrderByTwoWayStream onError: " +t.getMessage());
            }

            @Override
            public void onCompleted() {
                Log.d(TAG,"getOrderByTwoWayStream onCompleted.");
            }
        });
        observer.onNext(StringValue.newBuilder().setValue("1").build());
        observer.onNext(StringValue.newBuilder().setValue("2").build());
        observer.onCompleted();
    }

服务端

        在服务端OrderServer类中增加getOrderByTwoWayStream方法,具体实现如下:

  public StreamObserver<StringValue> getOrderByTwoWayStream(StreamObserver<OrderManagementOuterClass.Order> responseObserver) {
        return new StreamObserver<StringValue>() {
            @Override
            public void onNext(StringValue value) {
                Log.d(TAG," getOrderByTwoWayStream onNext request = " + value);
                responseObserver.onNext(OrderManagementOuterClass
                        .Order.newBuilder().setId(value.getValue() + "-1").build());
            }

            @Override
            public void onError(Throwable t) {
                Log.d(TAG," getOrderByTwoWayStream onError = " + t.getMessage());
            }

            @Override
            public void onCompleted() {
                Log.d(TAG," getOrderByTwoWayStream onCompleted");
                responseObserver.onCompleted();
            }
        };
    }

使用

          之后调用getOrderByTwoWayStream,具体实现如下:

 findViewById(R.id.bt_get_order_two_way_stream).setOnClickListener(v -> {
            workerClient.schedule(() ->{
                getOrderByTwoWayStream();
            });
        });

 public void getOrderByTwoWayStream(){
        client.getOrderByTwoWayStream();
    }

          执行结果如下所示:

2022-12-15 16:30:31.223 6092-6260/com.reactnative.grpcserverdemo D/OrderServer:  getOrderByTwoWayStream onNext request = # com.google.protobuf.StringValue@7c694
    value: "1"
2022-12-15 16:30:31.289 6092-6260/com.reactnative.grpcserverdemo D/OrderServer:  getOrderByTwoWayStream onNext request = # com.google.protobuf.StringValue@7c6c9
    value: "2"
2022-12-15 16:30:31.299 6092-6260/com.reactnative.grpcserverdemo D/OrderServer:  getOrderByTwoWayStream onCompleted
2022-12-15 16:30:31.304 6092-6260/com.reactnative.grpcserverdemo D/OrderClient: getOrderByTwoWayStream onNext : id = 1-1
2022-12-15 16:30:31.324 6092-6260/com.reactnative.grpcserverdemo D/OrderClient: getOrderByTwoWayStream onNext : id = 2-1
2022-12-15 16:30:31.328 6092-6260/com.reactnative.grpcserverdemo D/OrderClient: getOrderByTwoWayStream onCompleted.

最后附上demo下载地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/91831.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

破记录!国产数据库KunDB 单节点TPC-C事务性能超180万tpmC

近日&#xff0c;星环科技KunDB在TPC-C事务性能测试中&#xff0c;采用常规国产服务器&#xff0c;实现了单节点tpmC超180万&#xff0c;体现其世界级领先的事务处理能力。 TPC-C是全球 OLTP 数据库最权威的性能测试基准&#xff0c;由TPC组织&#xff08;国际事务性能委员会&…

【数字IC基础】TestBench功能

文章目录 一、TestBench的目的?二、TestBench的功能?三、TestBench(验证)的四要素?一、TestBench的目的? 对使用硬件描述语言(HDL)设计的电路(DUT)进行仿真验证,测试设计电路的功能、部分性能是否符合预期二、TestBench的功能? TestBench和DUT的关系是一个马蹄形结…

React - 项目初始化设置

React - 项目初始化设置一. 页面零边距二. 路径别名配置三. 安装使用 scss四. 安装 router一. 页面零边距 可以手写 css 重置页面样式&#xff0c;也可使用 reset-css 自动配置 手写样式不多说&#xff0c;这里使用 reset-css 安装依赖 yarn add reset-css src/App.js 文件中引…

阿里技术人分享的三本书豆瓣评分8.5分,让你的架构思维略窥门径

又逢“金九银十”&#xff0c;年轻的毕业生们满怀希望与忐忑&#xff0c;去寻找、竞争一个工作机会。已经在职的开发同学&#xff0c;也想通过社会招聘或者内推的时机争取到更好的待遇、更大的平台。 然而&#xff0c;面试人群众多&#xff0c;技术市场却相对冷淡&#xff0c;…

ssm+Vue计算机毕业设计校园疫情管理系统(程序+LW文档)

ssmVue计算机毕业设计校园疫情管理系统&#xff08;程序LW文档&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技…

我用了几行代码就实现了界面变灰效果

前言 前段时间,各个大厂的 App 首页都变成了灰色,网上还有不少人问界面变灰怎么做到的。有人说是后台换了图片,这个回答显然是不懂技术了,对于个性化推荐系统来说,使用的图片那么多张,怎么可能一一替换。还有一种说法是说后台将图片处理后再返回给前端的,这个显然也不太…

$ORACLE_BASE和$ORACLE_HOME下xml文件误删

问题描述&#xff1a; 某项目安装环境grid管理的oracle&#xff0c;环境已经搭建好许久&#xff0c;执行上线检查PSU版本时发现opatch lsinventory报错 但实例的sqlpatch显示已经应用成功且oracle client版本也显示为19.13 怀疑是Central Inventory&#xff08;/oracle/oraInv…

【知识图谱】(task4)知识图谱的抽取和构建

note CRF条件随机场是全局最优&#xff08;判别式模型&#xff09;&#xff0c;HMM是局部最优&#xff08;生成式模型&#xff09;实体关系抽取方法概览&#xff1a; 事件抽取主要分为事件的发现和分类和事件要素抽取两部分&#xff0c;又可以细分为触发词识别与事件分类和要素…

第13部分 VLAN,Trunk 和VTP

目录 13.1 VLAN&#xff0c;Trunk 和VTP 简介 13.1.1 VLAN 13.1.2 Trunk 13.1.3 VTP 13.1.4 EtherChannel 13.2 实验1&#xff1a;划分VLAN 1.实验目的 2.实验拓扑 3.实验步骤 4.实验调试 13.3 实验2&#xff1a;Trunk 配置 1.实验目的 2.实验拓扑 3.实验步骤 1…

SpringBoot整合Graylog做日志收集

日志收集折腾过程 ELK 之前整合过ELK做日志采集&#xff0c;就是Elasticsearch Logstash Kibana&#xff1a; Elasticsearch&#xff1a;存储引擎&#xff0c;存放日志内容&#xff0c;利于全文检索Logstash&#xff1a;数据传输管道&#xff0c;将日志内容传输到Elastics…

无法在Anaconda环境中使用pre-commit run --all-files:缺少匹配版本的ruamel.yaml

参考来源&#xff1a;https://stackoverflow.com/questions/68794749/unable-to-run-pre-commit-in-anaconda-environment 问题 与电脑两地隔离了半个月&#xff0c;今天开机commit的时候忽然弹出了下面的错误&#xff08;自己图忘存了&#xff0c;图源置顶链接&#xff09;&…

b站黑马的Vue快速入门案例代码——小黑记事本

目录 目标效果&#xff1a; 重点原理&#xff1a; &#xff08;1&#xff09;push&#xff08;&#xff09;方法——向数组末尾&#xff0c;添加新元素&#xff0c;并返回新长度 &#xff08;2&#xff09;v-on可以传递自定义参数&#xff0c;v-on:click”...“的简写是clic…

jdk11新特性——标准Java异步HTTP客户端

目录一、概述二、HTTP Client 同步发送请求使用示例2.1、创建简单的服务端2.2、创建HTTP Client 同步代码三、HTTP Client 异步发送请求使用示例3.1、创建简单的服务端&#xff08;参考2.1&#xff09;3.2、创建HTTP Client 异步代码一、概述 Java 9 开始引入的一个处理 HTTP …

浅谈ioremap,vmalloc,mmap三者之间的脉络

前言 系统mmu开启后, 程序对内存的访问都是虚拟地址, 之后mmu会自动将虚拟地址变为实际的物理地址&#xff08;硬件行为&#xff09;, 所以我们的程序如果要访问物理地址的话&#xff0c;必须要通过mmu建立虚拟地址与物理地址之间的映射关系。对于虚拟地址映射到物理地址的操作…

非零基础自学Golang 第7章 函数 7.6 延迟执行语句 7.7 小结

非零基础自学Golang 文章目录非零基础自学Golang第7章 函数7.6 延迟执行语句7.7 小结第7章 函数 7.6 延迟执行语句 Go语言中存在一种延迟执行的语句&#xff0c;由defer关键字标识&#xff0c;格式如下&#xff1a; defer 任意语句defer后的语句不会被马上执行&#xff0c;在…

Redis持久化详解

一、概述 在Redis中&#xff0c;实现高可用的技术主要包括持久化、复制、哨兵和集群&#xff0c;下面分别说明它们的作用&#xff0c;以及解决了什么样的问题。 持久化&#xff1a;持久化是最简单的高可用方法(有时甚至不被归为高可用的手段)&#xff0c;主要作用是数据备份…

springboot整合系列之如何选择版本及项目搭建

特别说明&#xff1a;本次项目整合基于idea进行的&#xff0c;如果使用Eclipse可能会略有不同。因为我很久没用过eclipse了&#xff0c;所以也没有办法给出两个版本。如果不一致的地方就自行google解决吧~~ springboot整合之如何选择版本及项目搭建 springboot整合mybatis-pl…

ADI Blackfin DSP处理器-BF533的开发详解52:图像处理专题-CMOS摄像头采集图像(含源码)

硬件准备 ADSP-EDU-BF533&#xff1a;BF533开发板 AD-HP530ICE&#xff1a;ADI DSP仿真器 软件准备 Visual DSP软件 硬件链接 功能介绍 板卡上设计了一个摄像头接口&#xff0c;可以连接与板卡匹配的 ADSP-EDU-CMOS 子卡板。摄像头接口采用 20PIN 插针接入&#xff0c;将插…

照片变漫画怎么做?分享这几个照片变漫画的技巧给你

大家在网上是否有看到过一些绘画博主给别人画漫画图呢&#xff1f;这些图片中的人物形象与现实中的非常相像&#xff0c;而且看起来真的很像漫画中的人物一般&#xff0c;画出来对于一些没有绘画功底的人来说是比较困难的。那么我们又该如何得到我们在漫画中的图片呢&#xff1…

四种常见排序(冒泡、选择、插入、快速排序)--- Python版

经典排序算法总结与实现 经典排序算法在面试中占有很大的比重&#xff0c;也是基础&#xff0c;为了未雨绸缪&#xff0c;这次收集整理并用Python实现了八大经典排序算法&#xff0c;包括冒泡排序&#xff0c;插入排序&#xff0c;选择排序&#xff0c;希尔排序&#xff0c;归…