RPC 服务与 gRPC 的入门案例

RPC 协议

RPC(Remote Procedure Call Protocol)即远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务的协议,允许一个计算机程序可以像调用本地服务一样调用远程服务

RPC的主要作用是不同的服务间方法调用就像本地调用一样便捷,它隐藏了网络通信的细节,使得开发者可以像调用本地函数一样调用远程函数,而无需关注底层网络通信的复杂性。

在这里插入图片描述

由于客户端和服务端部署在不同的机器上,服务间的调用就会涉及到网络通信,就需要写一堆网络通信相关的代码。
例如在调用 RESTful 服务时,调用端需要使用 HttpClient 设置很多参数,再去解析状态和返回值,非常复杂且易出错。
而 RPC 的方式可以让我们像调用本地服务一样调用远程服务,而且不必关心网络通信的细节。

RPC原理

Socket套接字

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端被称为 Socket。

Socket 用于描述 IP 地址和端口,是一个通信连接的句柄,可以用来实现不同的计算机之间的通信,是网络编程接口的具体实现。

Socket 套接字是客户端/服务端网络机构程序的基本组成部分,为程序提供了一种相对简单的机制,可以与另一个本地或远程机器上的程序建立连接,并可以来回发送消息。

我们可以使用它的收发消息功能来设计我们的分布式应用程序,也可以使用这些收发功能把 RPC 调用包装成透明的远程服务调用。

调用过程

实现透明的远程调用的重点是创建客户存根(类似于代理模式中的代理),在生成代理代码后,代理的代码就能与远程服务端通信了,通信的过程是由RPC 框架实现,而调用者就像调用本地代码一样。

对于客户端而言,存根函数就像普通的本地函数,但实际上包含了通过网络发送和接收消息的代码。

在这里插入图片描述

  • 第1 步,客户端调用本地的客户端存根方法,客户端存根方法会将参数打包并封装成一个或多个网络消息体并发送到服务端。
  • 第 2 步,客户端存根通过系统调用,使用操作系统内核提供的 Socket 套接字接口来向远程服务发送我们编码的网络消息。
  • 第 3 步,网络消息由内核通过协议(TCP/UDP)传输到远程服务端。
  • 第 4 步,服务端存根接收客户端发送的消息,并对参数消息解码,将参数从标准的网络格式转换为特定的语言格式。
  • 第 5 步,服务端存根调用服务端的方法,并且将从客户端接收的参数传递给该方法,它来运行具体的功能并返回,这部分代码的执行对客户端来说就是远程过程调用。
  • 第 6 步,服务端的方法在执行完成后,会把结果返回到服务端存根代码中。
  • 第 7 步,服务端存根在将该返回值编码且序列化后,通过一个或多个网络消息发送给客户端。
  • 第 8 步,消息通过网络发送到客户端存根中。
  • 第 9 步,客户端存根从本地 Socket 接口中读取结果消息。
  • 第 10 步,客户端存根再将结果返回给客户端函数,并且将消息从网络二进制形式转换为本地语言格式,这样就完成了远程服务调用,客户端代码继续执行后续的操作。

IDL接口

为了生成客户端和服务器的存根函数,我们需要定义一个远程调用接口的定义文件,该文件是使用一种叫做 IDL 的接口定义语言编写的。

接口定义类似于函数原型声明:函数名称、输入参数和返回参数。

在 RPC 编译器运行后,客户端和服务端的程序可以编译并链接到各自的存根函数。客户端存根必须实现初始化 RPC 通信的机制,找到服务器并进行连接,并能与远程服务器通信,并对远程过程调用失败的情况进行处理。

RPC框架-gRPC

gRPC 是 Google 主导开发的一个高性能开源的 RPC 框架,基于 HTTP/2 协议标准设计而成,并用 ProtoBuf 作为序列化工具和接口定义语言(IDL),支持多语言开发。

在这里插入图片描述

定义序列化数据结构

在一个.proto文件中定义数据的格式,这个格式由一系列messages组成,每个message包含多个字段,字段就是数据的名称和值的配对。

// The request message containing the user's name.
message HelloRequest {string name = 1;
}// The response message containing the greetings
message HelloReply {string message = 1;
}
}

接着通过.proto文件来定义gRPC服务,其中RPC方法的参数和返回类型都是上述定义的message

// The greeter service definition.
service Greeter {// Sends a greetingrpc SayHello (HelloRequest) returns (HelloReply) {}
}

最后通过protoc编译器以及gRPC插件来从.proto文件中生成代码。

protoc是Protocol Buffers的编译器,它能够根据.proto文件中定义的数据结构生成各种语言的数据访问类。在gRPC中,protoc与gRPC插件一起使用,可以生成gRPC客户端和服务器的代码,以及用于填充、序列化和检索消息类型的常规协议缓冲区代码。

实战

项目结构

在这里插入图片描述

  • api:存放公共代码;
  • server:服务端;
  • client:客户端。

api

1)首先引入需要的依赖

<properties><grpc.version>1.9.0</grpc.version><protobuf-java.version>3.5.1</protobuf-java.version>
</properties><dependencies><dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>${protobuf-java.version}</version></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-all</artifactId><version>${grpc.version}</version><exclusions><exclusion><artifactId>guava</artifactId><groupId>com.google.guava</groupId></exclusion></exclusions></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>24.1.1-jre</version></dependency><dependency> <!-- necessary for Java 9+ --><groupId>org.apache.tomcat</groupId><artifactId>annotations-api</artifactId><version>6.0.53</version><scope>provided</scope></dependency>
</dependencies>

2)引入插件

<build><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.5.0.Final</version></extension></extensions><plugins><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.5.1</version><configuration><protocArtifact>com.google.protobuf:protoc:3.5.1-1:exe:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin></plugins>
</build>

这个插件可以将我们编写的 .proto 文件自动转为对应的 Java 类。

3)创建 proto 目录,并定义.proto文件
在这里插入图片描述

syntax = "proto3";option java_package = "org.young.grpc.demo";package product;service ProductInfo {rpc addProduct (Product) returns (ProductId);rpc getProduct(ProductId) returns(Product);
}message Product {string id = 1;string name=2;string description=3;float price=4;
}message ProductId {string value = 1;
}

4)使用插件生成 java 代码
在这里插入图片描述

compilecompile-custom 都要执行, compile 用来编译消息对象,compile-custom 则依赖消息对象,生成接口服务。

在这里插入图片描述

server

server 项目依赖 api,在 server 中,提供 ProductInfo 的具体实现。

@Slf4j
public class ProductInfoImpl extends ProductInfoGrpc.ProductInfoImplBase {/*** @param request* @param responseObserver*/@Overridepublic void addProduct(ProductOuterClass.Product request, StreamObserver<ProductOuterClass.ProductId> responseObserver) {log.info("request:{}", request.toString());responseObserver.onNext(ProductOuterClass.ProductId.newBuilder().setValue(request.getId()).build()); // 方法响应responseObserver.onCompleted(); // 标记 RPC 调用完成}/*** @param request* @param responseObserver*/@Overridepublic void getProduct(ProductOuterClass.ProductId request, StreamObserver<ProductOuterClass.Product> responseObserver) {responseObserver.onNext(ProductOuterClass.Product.newBuilder().setId(request.getValue()).setName("test_grpc").build());responseObserver.onCompleted();}
}

然后再启动该项目

public class ServerBootStrap {Server server;public static void main(String[] args) throws Exception {ServerBootStrap serverBootStrap = new ServerBootStrap();serverBootStrap.start();serverBootStrap.blockUntilShutdown();}void start() throws Exception{server = NettyServerBuilder.forPort(50091).addService(new ProductInfoImpl()).build().start();Runtime.getRuntime().addShutdownHook(new Thread() {@Overridepublic void run() {ServerBootStrap.this.stop();}});}private void stop() {if (server != null) {server.shutdown();}}private void blockUntilShutdown() throws InterruptedException {if (server != null) {server.awaitTermination();}}
}

client

client 项目也需要依赖 api ,然后直接进行方法调用,如下:

@Slf4j
public class GrpcClient {public static void main(String[] args) {ManagedChannel managedChannel = ManagedChannelBuilder.forAddress("localhost", 50091).usePlaintext(true).build();ProductInfoGrpc.ProductInfoBlockingStub stub = ProductInfoGrpc.newBlockingStub(managedChannel);ProductOuterClass.Product req = ProductOuterClass.Product.newBuilder().setId("1").setPrice(100.0f).setName("test-grpc").setDescription("test-grpc").build();ProductOuterClass.ProductId productId = stub.addProduct(req);log.info("productId.getValue:{}", productId.getValue());ProductOuterClass.Product product = stub.getProduct(ProductOuterClass.ProductId.newBuilder().setValue("99999").build());log.info("product:{}", product.toString());}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习-正则化技术

文章目录 拟合正则化正则项L1 正则化&#xff08;Lasso&#xff09;L2 正则化&#xff08;Ridge&#xff09; 多元线性回归的正则化回归形式代码 拟合 过拟合&#xff1a;参数&#xff08;特征&#xff09;过多&#xff08;理解为考虑很多因素)或者说过多专注于原来的训练数据…

数据可视化-2. 条形图

目录 1. 条形图适用场景分析 1.1 比较不同类别的数据 1.2 展示数据分布 1.3 强调特定数据点 1.4 展示时间序列数据的对比 1.5 数据可视化教育 1.6 特定领域的应用 2. 条形图局限性 3. 条形图图代码实现 3.1 Python 源代码 3.2 条形图效果&#xff08;网页显示&#…

【DBeaver】连接带kerberos的hive[Apache|HDP]

目录 一、安装配置Kerberos客户端环境 1.1 安装Kerberos客户端 1.2 环境配置 二、基于Cloudera驱动创建连接 三、基于Hive原生驱动创建连接 一、安装配置Kerberos客户端环境 1.1 安装Kerberos客户端 在Kerberos官网下载,地址如下&#xff1a;https://web.mit.edu/kerberos…

SpringBoot+IDEA工具框架快捷键+注解备注

快捷键 ctrlr 搜索替换 ctrlshiftr 全局搜索和替换 altfninsert 自行补全函数和构造函数等 ctrlaltt 可以尝试添加东西 可以加try catch ctrlshiftt 生成接口对应的测试函数 ctrlh 可以查看当前类的一个继承和实现关系 大写CD回车 ide会自动生成cdata区的标签 x…

AI前沿分析:ChatGPT搜索上线,Google搜索地位能否守住?

名人说&#xff1a;莫听穿林打叶声&#xff0c;何妨吟啸且徐行。—— 苏轼 Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 引言&#xff1a;AI与搜索领域的激烈博弈一、ChatGPT搜索的优势是什么&#xff1f;1. 实时信息获取&#xf…

ScottPlot学习的常用笔记

ScottPlot学习的常用笔记 写在前面版本的选择第一个障碍&#xff1a;版本问题。 ScottPlot4.0的官方网站与示例官方起始页cookbook5.0Demo4.1 demo以4.1为例&#xff0c;解压和运行如下&#xff1a; 下载源代码和编译先说结论&#xff1a; 写在前面 之前调研的TraceCompass&am…

客户端(浏览器)vue3本地预览txt,doc,docx,pptx,pdf,xlsx,csv,

预览文件 1、入口文件preview/index.vue2、预览txt3、预览doc4、预览pdf5、预览pptx6、预览xlsx7、预览csv 1、入口文件preview/index.vue 预览样式&#xff0c;如pdf 文件目录如图所示&#xff1a; 代码如下 <template><div class"preview-wrap" ref&…

luckysheet与superslide冲突解决

[现象]控制台报错、界面无法操作 $是jquery。查看源码&#xff0c;发现mousewheel方法来自插件mousewheel&#xff0c;luckysheet初始应该会将mousewheel挂载在jquery上。 在控制台打印jquery取dom及其方法&#xff0c;结果如下&#xff1a; 不存在mousewheel方法&#xff0c…

MongoDB(上)

MongoDB 基础 MongoDB 是什么&#xff1f; MongoDB 是一个基于 分布式文件存储 的开源 NoSQL 数据库系统&#xff0c;由 C 编写的。MongoDB 提供了 面向文档 的存储方式&#xff0c;操作起来比较简单和容易&#xff0c;支持“无模式”的数据建模&#xff0c;可以存储比较复杂…

搭建Tomcat(四)---Servlet容器

目录 引入 Servlet容器 一、优化MyTomcat ①先将MyTomcat的main函数搬过来&#xff1a; ②将getClass()函数搬过来 ③创建容器 ④连接ServletConfigMapping和MyTomcat 连接&#xff1a; ⑤完整的ServletConfigMapping和MyTomcat方法&#xff1a; a.ServletConfigMappin…

构建一个rust生产应用读书笔记四(实战3)

从这一节开始&#xff0c;我们将继续完善邮件订阅生产级应用&#xff0c;根据作者的选型sqlx作为数据库操作的类库&#xff0c;它有如下优点&#xff1a; 它旨在提供高效、安全且易于使用的数据库交互体验。sqlx 支持多种数据库&#xff0c;包括 PostgreSQL、MySQL 和 SQLite&…

网络安全-------防止被抓包

1.Ios应用网络安全之https 安全套接字层 (Secure Socket Layer, SSL) 是用来实现互联网安全通信的最普遍的标准。Web 应用程序使用 HTTPS&#xff08;基于 SSL 的 HTTP&#xff09;&#xff0c;HTTPS 使用数字证书来确保在服务器和客户端之间进行安全、加密的通信。在 SSL 连接…

WebSocket 与 Server-Sent Events (SSE) 的对比与应用

目录 ✨WebSocket&#xff1a;全双工通信的利器&#x1f4cc;什么是 WebSocket&#xff1f;&#x1f4cc;WebSocket 的特点&#x1f4cc;WebSocket 的优点&#x1f4cc;WebSocket 的缺点&#x1f4cc;WebSocket 的适用场景 ✨Server-Sent Events (SSE)&#xff1a;单向推送的轻…

CAD c# 生成略缩图预览

代码如下&#xff1a; using (Transaction tr currentdb.TransactionManager.StartTransaction()){//当前数据库开启事务using (Database tempdb new Database(false, true)) //创建临时数据库(两个参数&#xff1a;是否创建符号表&#xff0c;不与当前文档关联){try{Bitmap …

娱乐五子棋(附加源码)

一写在开头 上期代码主要实现瀑布流功能&#xff0c;本期就来实现五子棋小游戏&#xff0c;开发久了很多功能都是通过框架组件库来完成&#xff0c;但是如果组件满足不了开发需求&#xff0c;还需要开发人员手动封装组件&#xff0c;专门出这样一期文章&#xff0c;通过原生js实…

XMOS将在CES 2025上展出多款由边缘AI驱动的创新音效、音频、识别和处理解决方案

全球智能物联网技术领导者暨匠心独到的半导体科技企业XMOS宣布&#xff1a;该公司将再次参加2025年国际消费电子展&#xff08;CES 2025&#xff09;&#xff0c;并将在本届CES上展出一系列由人工智能&#xff08;AI&#xff09;驱动的全新空间音效、语音捕获与降噪、音视频多模…

HCIA-Access V2.5_2_2_2网络通信基础_IP编址与路由

网络层数据封装 首先IP地址封装在网络层&#xff0c;它用于标识一台网络设备&#xff0c;其中IP地址分为两个部分&#xff0c;网络地址和主机地址&#xff0c;通过我们采用点分十进制的形式进行表示。 IP地址分类 对IP地址而言&#xff0c;它细分为五类&#xff0c;A,B,C,D,E,…

我的数据仓库与数据挖掘期末大作业重置版

文章目录 我的数据仓库与数据挖掘期末大作业重置版准备工作预设定及导入相对应的库库的导入调整 Jupyter Notebook 的预设定调整 MatPlotLib 和 Pandas 的输出设置 任务 1&#xff1a;预测问题数据的保存和读取数据的分析和预处理模型的选择和构建线性回归一元多项式回归 拟合预…

CUDA C编程权威指南习题解析

文章目录 一、1.6节习题二、2.6习题三、四、五、六、 一、1.6节习题 1.参考图1-5&#xff0c;分析以下几种数据划分形式&#xff1a; &#xff08;1&#xff09;对于二维数据&#xff0c;沿x轴进行块划分 &#xff08;2&#xff09;对于二维数据&#xff0c;沿y轴进行周期划…

cocos creator 的 widget组件的使用及踩坑

以下的内容基于cocos creator 3.8版本&#xff0c;如有错误&#xff0c;恳请指出。 &#x1f449;官方文档的指引 应用&#xff1a;以上官方指引有非常清晰的使用方式&#xff0c;接下来说明一些注意事项&#xff1a; 1、与canvas搭配的使用&#xff0c;解决多分别率适配问题。…