[gRPC实现go调用go]

1什么是RPC

RPC:Remote Procedure Call,远程过程调用。简单来说就是两个进程之间的数据交互。正常服务端的接口服务是提供给用户端(在Web开发中就是浏览器)或者自身调用的,也就是本地过程调用。和本地过程调用相对的就是:假如两个服务端不在一个进程内怎么进行数据交互?使用RPC。尤其是现在微服务的大量实践,服务与服务之间的调用不可避免,RPC更显得尤为重要

在这里插入图片描述

上图描述了一个RPC的完整调用流程:
1:client向client stub发起方法调用请求。
2:client stub接收到请求后,将方法名,请求参数等信息进行编码序列化。
3:client stub通过配置的ip和端口使用socket通过网络向远程服务器server发起请求。
4:远程服务器server接收到请求,解码反序列化请求信息。
5:server将请求信息交给server stub,server stub找到对应的本地真实方法实现。
6:本地方法处理调用请求并将返回的数据交给server stub。
7:server stub 将数据编码序列化交给操作系统内核,使用socket将数据返回。
8:client端socket接收到远程服务器的返回信息。
9:client stub将信息进行解码反序列化。
10:client收到远程服务器返回的信息。

上图中有一个stub(存根)的概念。stub负责接收本地方法调用,并将它们委托给各自的具体实现对象。server端stub又被称为skeleton(骨架)。可以理解为代理类。而实际上基于Java的RPC框架stub基本上也都是使用动态代理。我们所说的client端和server端在RPC中一般也都是相对的概念。
而所谓的RPC框架也就是封装了上述流程中2-9的过程,让开发者调用远程方法就像调用本地方法一样。

2. gRPC的原理

gRPC是Google的开源产品,是跨语言的通用型RPC框架,使用Go语言编写。 Java语言的应用同样使用了Netty做网络通信,Go采用了Goroutine做网络通信。序列化方式采用了Google自己开源的Protobuf。请求的调用和返回使用HTTP2的Stream。

一个RPC框架必须有两个基础的组成部分:数据的序列化和进程数据通信的交互方式。

对于序列化gRPC采用了自家公司开源的Protobuf。Google Protocol Buffer(简称 Protobuf)是一种轻便高效的结构化数据存储格式,平台无关、语言无关、可扩展,可用于通讯协议和数据存储等领域。似乎和我们熟悉的JSON类似,但其实着重点有些本质的区别。JSON主要是用于数据的传输,因为它轻量级,可读性好,解析简单。Protobuf主要是用于跨语言的IDL,它除了和JSON、XML一样能定义结构体之外,还可以使用自描述格式定于出接口的特性,并可以使用针对不同语言的protocol编译器产生不同语言的stub类。所以天然的适用于跨语言的RPC框架中(非常重要)

而关于进程间的通讯,无疑是Socket。Java方面gRPC同样使用了成熟的开源框架Netty。使用Netty Channel作为数据通道。传输协议使用了HTTP2。
通过以上的分析,我们可以将一个完整的gRPC流程总结为以下几步:

● 通过.proto文件定义传输的接口和消息体。
● 通过protocol编译器生成server端和client端的stub程序。
● 将请求封装成HTTP2的Stream。
● 通过Channel作为数据通信通道使用Socket进行数据传输。

3 实践开始

下面我们使用代码基于以上的步骤来实现一个简单gRPC。我们用Go实现server端,Java作为client端来实现。

3.1 安装Protocol Buffers,定义.proto文件

下载Protocol Buffers:https://github.com/protocolbuffers/protobuf/releases
检查安装

protoc --version

定义一个simple.proto,这也是后续实现gRPC的基础:

syntax = "proto3"; //定义了我们使用的Protocol Buffers版本。option go_package = "./;simple";//***在java端请注释本行***//表明我们定义了一个命名为Simple的服务(接口),内部有一个远程rpc方法,名字为SayHello。//我们只要在server端实现这个接口,在实现类中书写我们的业务代码。在client端调用这个接口。service Simple{rpc SayHello(HelloRequest) returns (HelloReplay){}}//请求的结构体message HelloRequest{string name = 1;}//返回的结构体message HelloReplay{string message = 1;}

3.2 在Go端实现server

根据官方文档使用如下命令安装针对Go的gRPC:

go get -u google.golang.org/grpc

建立Go的project:go-server-grpc,然后将前面写的simple.proto放入项目proto的package中。
cd到proto目录执行如下命令:

protoc --go_out=plugins=grpc:. simple.proto

这样就将simple.proto编译成了Go语言对应的stub程序了。
在这里插入图片描述

随后我们就可以写我们server端的代码了:main.go。
以下的代码都是模板代码,main函数是socket使用Go的标准实现。作为开发者我们只关注远程服务提供的具体接口实现即可。
我们可以在生成的simple.pb.go中发现需要实现的接口:

// 客户端调用的接口
type SimpleClient interface {SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReplay, error)
}type simpleClient struct {cc grpc.ClientConnInterface
}func NewSimpleClient(cc grpc.ClientConnInterface) SimpleClient {return &simpleClient{cc}
}func (c *simpleClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReplay, error) {out := new(HelloReplay)err := c.cc.Invoke(ctx, "/Simple/SayHello", in, out, opts...)if err != nil {return nil, err}return out, nil
}// 服务端需要实现的接口
type SimpleServer interface {SayHello(context.Context, *HelloRequest) (*HelloReplay, error)
}

之后我们在main.go中实现接口:

package mainimport ("context""grpc-server/proto"//引入对应的包"fmt""net""log""google.golang.org/grpc""google.golang.org/grpc/reflection"
)
//定义接下来要开放的socket的端口
const(port = ":50051"
)type server struct{}func (s *server) SayHello(ctx context.Context,req *simple.HelloRequest) (*simple.HelloReplay, error){fmt.Println(req.Name)return &simple.HelloReplay{Message:"hello =======> " + req.Name},nil
}

之后填写main方法:

func main() {//创建一个socket监听lis, err := net.Listen("tcp", port)if err != nil {log.Fatal("fail to listen")}//新建一个grpc服务器s := grpc.NewServer()//使用 simple.RegisterSimpleServer 函数将实现了 SimpleServer 接口的 server 对象注册到 gRPC 服务器(s)上simple.RegisterSimpleServer(s, &server{})//使用 reflection.Register 函数将 gRPC 服务器(s)注册到反射服务中。这样,可以通过 gRPC 提供的工具来动态地查看和调用服务器上的服务。reflection.Register(s)//使用 s.Serve 方法启动 gRPC 服务器(s),开始接受来自客户端的连接请求并提供服务。如果启动过程中出现错误,程序会输出一条错误信息并终止运行。if err := s.Serve(lis); err != nil {log.Fatal("fail to server")}
}

目前服务端已经完成了。

3.3 在Go端实现client

package mainimport ("context""fmt"simple "go-server-grpc/proto""log""google.golang.org/grpc"
)const (address = "localhost:50051"
)func main() {// 创建与服务器的连接conn, err := grpc.Dial(address, grpc.WithInsecure())if err != nil {log.Fatalf("无法连接到服务器:%v", err)}defer conn.Close()// 创建一个新的 gRPC 客户端client := simple.NewSimpleClient(conn)// 构建请求request := &simple.HelloRequest{Name: "John",}// 调用 gRPC 方法response, err := client.SayHello(context.Background(), request)if err != nil {log.Fatalf("调用 gRPC 方法失败:%v", err)}// 打印响应fmt.Println(response.Message)
}

需要先启动服务端,再启动客户端就可以看到效果。
输出:hello=======>John

4.下次预告

实现Java作为客户端调用go服务端的服务

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

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

相关文章

深度优先遍历(DFS)

时间复杂度与深搜一致;

STM32 定时器总结

缩写 ARR: Auto-Reload Register(保存定时器的计数范围) PSC: Prescaler register(预分频器寄存器,根据设置的分频因子N,计数N个定时器时钟脉冲后,产生一个CNT计数,以此实现分频功能&#xff0…

LeetCode 2048. 下一个更大的数值平衡数

一、题目 1、题目描述 如果整数 x 满足&#xff1a;对于每个数位 d &#xff0c;这个数位 恰好 在 x 中出现 d 次。那么整数 x 就是一个 数值平衡数 。 给你一个整数 n &#xff0c;请你返回 严格大于 n 的 最小数值平衡数。 0 < n < 1e6 2、接口描述 public:int nextB…

Android渲染-AHardwareBuffer

本文主要从应用的角度介绍android的native层AHardwareBuffer创建纹理以及保存渲染数据。 HardwareBuffer 要介绍native层的AHardwareBuffer&#xff0c;就需要先从Java层的HardwareBuffer说起。Android官方对于HardwareBuffer介绍如下&#xff1a; HardwareBuffer wraps a na…

HttpURLConnection OOM问题记录

使用HttpURLConnection 上传大文件&#xff0c;会出现内存溢出问题&#xff1a; 观察HttpURLConnection 源码&#xff1a; Overridepublic synchronized OutputStream getOutputStream() throws IOException {connecting true;SocketPermission p URLtoSocketPermission(th…

【接口分享】热门好用的API,含免费次数

语音验证码短信&#xff1a;拨打电话告知用户验证码&#xff0c;实现信息验证。短信验证码&#xff1a;可用于登录、注册、找回密码、支付认证等等应用场景。支持三大运营商&#xff0c;3秒可达&#xff0c;99.99&#xff05;到达率&#xff0c;支持大容量高并发。通知短信&…

基于SSM的点餐系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

mysql设置为密码登录

要设置Ubuntu上的MySQL需要密码登录&#xff0c;你可以使用以下步骤&#xff1a; 打开终端。 输入以下命令登录到 MySQL 服务器&#xff1a; sudo mysql -u root -p按Enter后&#xff0c;系统会要求输入密码。如果是第一次登录&#xff0c;你可能需要直接按Enter键&#xff08…

【已解决】解决UbuntuKali无法进行SSH远程连接

目录 Ubuntu20.04配置SSH远程连接Kali Linux配置SSH远程连接 Ubuntu20.04配置SSH远程连接 首先更新安装包 sudo apt-get update 下载SSH服务 sudo apt install openssh-server 查看SSH服务 service ssh status 打开 /etc/ssh/sshd_config文件修改配置文件 将PermitRootLog…

知识笔记(五十二)———MySQL 删除数据表

MySQL中删除数据表是非常容易操作的&#xff0c;但是你在进行删除表操作时要非常小心&#xff0c;因为执行删除命令后所有数据都会消失。 语法 以下为删除 MySQL 数据表的通用语法&#xff1a; DROP TABLE table_name ; -- 直接删除表&#xff0c;不检查是否存在 或 DROP…

基于Debain安装 Docker 和 Docker Compose

一、安装Docker # 先升级一下系统 (Ubuntu / Debian 系) sudo apt-get update sudo apt-get upgrade# 如果你是 CentOS、红帽系列则使用&#xff1a; yum update yum upgrade# 安装 Docker curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh二、Dock…

LeetCode 0070. 爬楼梯:动态规划(递推)

【LetMeFly】70.爬楼梯&#xff1a;动态规划&#xff08;递推&#xff09; 力扣题目链接&#xff1a;https://leetcode.cn/problems/climbing-stairs/ 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#x…

NVIDIA Jetson NX ubuntu20.04删除多余版本冲突的Boost库

参考Ubuntu16.04 卸载旧版本Boost库并安装新版本 卸载 删除/usr/local/include/boost文件夹&#xff0c;删除/usr/local/lib中和boost有关的文件,以及/usr/local/lib/cmake/中boost的cmake文件 cd /usr/local/lib/ ls | grep boost sudo rm -rf /usr/local/include/boost su…

蓝桥杯 day01 奇怪的数列 特殊日期

奇怪的数列 题目描述 奇怪的数列 从 X 星截获一份电码&#xff0c;是一些数字&#xff0c;如下&#xff1a; 13 1113 3113 132113 1113122113 ⋯⋯ YY 博士经彻夜研究&#xff0c;发现了规律&#xff1a; 第一行的数字随便是什么&#xff0c;以后每一行都是对上一行…

redis+springsecurity+mybtais-plus+JWT

redisspringsecuritymybtais-plusJWT 01 引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.mysql</groupId&g…

12.视图

目录 1.视图的含义与作用 2.视图的创建与查看 1.创建视图的语法形式 2、查看视图&#xff1a; 1.使用DESCRIBE语句查看视图基本信息 2.使用SHOW TABLE STATUS语查看视图基本信息查看视图的信息 3.使用SHOW CREATE VIEW语查看视图详细信息 4.在views表中查看视图详细信息…

【DP】Yarik and Array—CF1899C

Yarik and Array—CF1899C 一道不难的DP&#xff0c;根据代码就能看出思路。 C o d e Code Code #include <bits/stdc.h> #define int long long #define sz(a) ((int)a.size()) #define all(a) a.begin(), a.end() using namespace std; using PII pair<int, int&…

codeforces

分析 删去 k k k 个之后要是回文串&#xff0c;不过题目会给字符串rearrange&#xff0c;所以对于奇数个数的字符最多留一个&#xff0c;偶数的不用管。 Think Twice, Code Once #include<bits/stdc.h> #define il inline #define get getchar #define put putchar #…

SAP-PP:PP模块新手顾问入门寻找解决方案途径

在学习PP模块时我们可以参考一下部分资源: SAP Help SAP Help SAP 帮助门户是了解任何功能基础知识的起点。在这里&#xff0c;您将了解每个功能可以做什么&#xff0c;以及如何使用每个功能的一些基本示例 F1 Help 每个事务中的每个字段都有自己的文档&#xff0c;您可以通过…

案例015:基于微信小程序的校园防疫系统

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…