【GoWeb框架初探——GRPC】

1. GRPC介绍

1.1 什么是RPC

RPC全程是Remote Procedure Call,远程过程调用。这是一种协议,是用来屏蔽分布式计算中的各种调用细节,使得你可以像是本地调用一样直接调用一个远程的函数。

调用流程
1)客户端发送数据(以字节流的方式)编码
2)服务端接受并解析。根据约定知道要执行什么,然后把结果返回给客户 解码

1、RPC就是将上述过程封装起来,使得操作更加优化。
2、使用一些大家都认可的协议,使其规范化

1.2 什么是GRPC

gRPC是谷歌开源的一个高性能的、开源的通用的RPC框架。
我们称调用方为client,被调用方为server。跟其他的RPC框架一样,gRPC也是基于”服务定义“的思想。简单来说就是我们通过某种方式来描述一个服务,这种描述方式是语言无关的。在这个"服务定义"的过程中,我们描述了我们提供的服务服务名是什么,有哪些方法可以被调用,这些方法有什么样的入参,有什么样的回参。

也就是说,在定义好了这些服务、这些方法之后,gRPC会屏蔽底层的细节,clent只需要直接调用定义好的方法,就能拿到预期的返回结果、对于server端来说,还需要实现我们定义的方法。同样的,gRPC也会帮我们屏蔽底层的细节,我们只需要实现所定义的方法的具体逻辑即可。

你可以发现,在上面的描述过程中,所谓的”服务定义",就跟定义接口的语义是很接近的。我更愿意理解为这是一种"约定"”,双方约定好接口,然后server实现这个接口,client调用这个接口的代理对象。至于其他的细节,交给gRPC.此外,gRPC还是语言无关的。你可以用C++作为服务端,使用Golang、Java等作为客户端。为了实现这一点,我们在"定义服务“和在编码和解码的过程中,应该是做到语言无关的。

在这里插入图片描述

1.3 Protocol Buffers

数据在传输的过程中使用的都是二进制流。gRPC使用了Protocol Buffers,这是谷歌开源的一套成熟的数据结构序列化机制

protobut是谷歌开源的一种数据格式,适合高性能,对响应速度有要求的数据传输场景。因为profobuf是二进制数据格式,需要编码和解码。数据本身不具有可读性。因此只能反序列化之后得到真正可读的数据。
优点:

  1. 序列化后体积相比json和XML很小,适合网络传输
  2. 支持跨平台多语言
  3. 消息格式升级和兼容性还不错
  4. 序列化和反序列化速度很快

利用这个工具可以把我们定义的方法,转换成特定语言的代码,比如你定义了一种类型的参数,他会帮你转换成Glang中的strudt 结构体,你定义的方法,他会帮你转换成func 函教。此外,在发送请求和接受响应的时候,这个工具还会完成对应的编码和解码工作,将你即将发送的数据编码成RPC能够传输的形式,又或者将即将接收到的数据解码为编程语言能够理解的数据格式。

序列化:将数据结构或对象转换成二进制串的过程
反序列化:将在序列化过程中所产生的二进制串转换成数据结构或者对象的过程

2.protobuf文件编写

hello.proto文件

// 使用的proto的版本
syntax = "proto3";

// 这部分的内容是关于最后生成的go文件是处在哪个目录哪个包中,代表在当前目录生成,service代表了生成的go文件的包名是service
option go_package = ".;service";

// 定义服务
service SayHello{
  rpc SayHello(HelloRequest) returns (HelloResponse){}
}

// message关键字,定义结构体变量
message HelloRequest{
  string requestName = 1;
  int64 age = 2;
  // 定义相关的数组
  // repeated string follows = 3;
}

message HelloResponse{
  string responseMsg = 1;
}

在hello.proto文件夹下运行以下命令生成对应的文件:

protoc --go_out=. hello.proto
protoc --go-grpc_out=. hello.proto

3. 服务端编写

  • 创建gRPC Server对象,你可以理解为它是Server端的抽象对象
  • 将server(其包含需要被调用的服务端接口)注册到gRPC Server的内部注册中心。这样可以在接受到请求时,通过内部的服务发现,发现该服务器端接口并转接进行逻辑处理
  • 创建Listen,监听TCP端口
  • gRPC Server开始lis.Accept,直到Stop
package main

import (
	"context"
	"fmt"
	hello "go-grpc/hello-server/proto"
	"google.golang.org/grpc"
	"log"
	"net"
	"strconv"
)

type HelloService struct {
	hello.UnimplementedSayHelloServer
}

func (ds *HelloService) SayHello(ctx context.Context, in *hello.HelloRequest) (*hello.HelloResponse, error) {
	fmt.Println("服务器的方法被调用了")
	return &hello.HelloResponse{ResponseMsg: in.RequestName + strconv.Itoa(int(in.Age))}, nil
}

func main() {
	//绑定9091端口
	listener, err := net.Listen("tcp", ":10005")
	if err != nil {
		log.Fatalf("bingding port:9091 error:%v", err)
	}

	grpcServer := grpc.NewServer()
	var impliServer = &HelloService{}
	hello.RegisterSayHelloServer(grpcServer, impliServer)
	log.Printf("server listening at %v", listener.Addr())
	if err := grpcServer.Serve(listener); err != nil {
		panic("error building server: " + err.Error())
	}
}

4.客户端编写

  • 创建与给定目标(服务端)的连接交互
  • 创建server的客户端对象
  • 发送RPC请求,等待同步响应,得到回调后返回响应结果
  • 输出响应结果
package main

import (
	"context"
	"flag"
	hello "go-grpc/hello-client/proto"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"log"
	"time"
)

var (
	address = flag.String("address", "localhost:10005", "the address connect to ")
)

func main() {

	flag.Parse()
	connection, err := grpc.Dial(*address, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("connect localhost:9091 fail:%v\n", err)
	}
	defer connection.Close()

	client := hello.NewSayHelloClient(connection)
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
	defer cancel()

	response, err := client.SayHello(ctx, &hello.HelloRequest{RequestName: "jack", Age: 19})
	if err != nil {
		log.Fatalf("client call server Sender method fail:%v\n", err)
	} else {
		log.Println("rpc returns result:", response.ResponseMsg)
	}
	//获取StudentResponse result的内容
}

5. TLS认证连接

TLS(传输层安全)是一种加密协议,用于在客户端和服务器之间建立安全的通信连接。TLS 在网络通信中起着至关重要的作用,尤其是在保护敏感数据的传输过程中,比如网上银行、电子邮件等。

5.1 修改openssl.cnf

在这里插入图片描述

5.2 生成证书

# 1、生成私钥
openssl genrsa -out server.key 2048
# 2、生成证书
openssl req -new -x509 -key server.key -out server.crt -days 36500
# 3、生成csr
openssl req -new -key server.key -out
# 4、生成证书的私钥
openssl genpkey -algorithm RSA -out test.key
# 5、通过私钥test.key生成证书请求文件test.csr
openssl req -new -nodes -key test.key -out test.csr -days 3650 -subj "/C=cn/OU=myorg/O=mycomp/CN=myname" -config ./openssl.cnf -extensions v3_req

# 6、生成SAN证书 pem
openssl x509 -req -days 365 -in test.csr -out test.pem -CA server.crt -CAkey server.key -CAcreateserial -extfile ./openssl.cnf -extensions  v3_req 

在这里插入图片描述

5.3 修改客户端和服务端代码

server.go

func main() {
	//=====================
	//TSL认证
	//=====================
	//两个参数分别是cretFile,keyFile
	//自签名证书文件和私钥文件
	creds, err := credentials.NewServerTLSFromFile("absolutePath/key/test.pem", "absolutePath/key/test.key")
	if err != nil {
		return
	}
	//绑定9091端口
	listener, err := net.Listen("tcp", ":10005")
	if err != nil {
		log.Fatalf("bingding port:9091 error:%v", err)
	}
	grpcServer := grpc.NewServer(grpc.Creds(creds))
	var impliServer = &HelloService{}
	hello.RegisterSayHelloServer(grpcServer, impliServer)
	log.Printf("server listening at %v", listener.Addr())
	if err := grpcServer.Serve(listener); err != nil {
		panic("error building server: " + err.Error())
	}
}

client.go

func main() {
	// 使用证书认证ß
	creds, err := credentials.NewClientTLSFromFile("absolutePath/key/test.pem", "*.kuangstudy.com")
	flag.Parse()
	connection, err := grpc.Dial(*address, grpc.WithTransportCredentials(creds))
	if err != nil {
		log.Fatalf("connect localhost:9091 fail:%v\n", err)
	}
	defer connection.Close()

	client := hello.NewSayHelloClient(connection)
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
	defer cancel()

	response, err := client.SayHello(ctx, &hello.HelloRequest{RequestName: "jack", Age: 19})
	if err != nil {
		log.Fatalf("client call server Sender method fail:%v\n", err)
	} else {
		log.Println("rpc returns result:", response.ResponseMsg)
	}
	//获取StudentResponse result的内容
}

6. Token认证

实现接口方法:

// PerRPCCredentials 定义了需要为每个 RPC 附加安全信息的凭据的通用接口(例如,oauth2)。
type PerRPCCredentials interface {
	GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)
	// RequireTransportSecurity 指示凭据是否需要传输安全性。
	RequireTransportSecurity() bool
}

6.1 客户端附带信息

type ClientTokenAuth struct {
}

func (c ClientTokenAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {

	return map[string]string{
		"appId":  "kuangshen",
		"appKey": "123123",
	}, nil
}

// 是否开启安全加密
func (c ClientTokenAuth) RequireTransportSecurity() bool {
	return false
}

6.2 服务端处理信息

这段代码本来应该写在拦截器里,这里偷懒写在服务里了

func (ds *HelloService) SayHello(ctx context.Context, in *hello.HelloRequest) (*hello.HelloResponse, error) {
	// 获取原数据的信息
	md, ok := metadata.FromIncomingContext(ctx)
	if !ok {
		return nil, errors.New("未传入tokem")
	}
	var appId string
	var appKey string
	if v, ok := md["appid"]; ok {
		appId = v[0]
	}
	if v, ok := md["appkey"]; ok {
		appId = v[0]
	}
	//
	if appId != "kuangshen" || appKey != "123123" {
		return nil, errors.New("Token 不正确")
	}

	fmt.Println("服务器的方法被调用了")
	return &hello.HelloResponse{ResponseMsg: in.RequestName + strconv.Itoa(int(in.Age))}, nil
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

flutter 谷歌的苹果系统消息推送

flutter firebase 云消息通知教程 (android-安卓、ios-苹果) Android、ReactNative、Flutter集成Firebase推送注意事项 Android:Firebase 凭据 iOS:基于 p8 令牌的 APN 连接 iOS:p12 生成证书 Flutter之对接国外推送onesignal踩坑笔记&a…

基于SSM的平面设计课程在线学习平台系统(有报告)。Javaee项目。ssm项目。

演示视频: 基于SSM的平面设计课程在线学习平台系统(有报告)。Javaee项目。ssm项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构,…

C++:STL-list模拟实现:迭代器的封装

STL-list模拟实现细节 一. 模拟实现的思想细节1.迭代器实现:用类进行封装2.和--的重载3.奇怪的->重载4.const迭代器 二.实现源码 一. 模拟实现的思想细节 1.迭代器实现:用类进行封装 为什么不使用原生指针: ​ 相比于vector和string&am…

9.Godot数组|遍历|静态变量|对象|调试

数组和字典的遍历 数组的概念 数组是一组数据的集合。在程序中负责批量处理数据。数组中的元素可以包括各个类型的数据,也可以对数组内数据类型进行限定。可以通过 数组名【数字】 的形式来访问数组元素,数字 0 代表数组的第一个元素。数组可以通过调用…

《中学科技》是什么级别的刊物?如何投稿?

《中学科技》是什么级别的刊物?如何投稿? 《中学科技》创刊于1976年,由上海世纪出版(集团)有限公司主管,上海科技教育出版社有限公司主办的省级学术期刊,《中学科技》以传播科技知识、启迪智慧…

蓝桥杯2024年第十五届省赛真题-宝石组合

思路:参考博客,对Ha,Hb,Hc分别进行质因数分解会发现,S其实就等于Ha,Hb,Hc的最大公约数,不严谨推导过程如下(字丑勿喷): 找到此规律后,也不能枚举Ha&#xff…

AI容器化部署开发尝试 (一)(Pycharm连接docker,并部署django测试)

注意:从 Docker 19.03 开始,Docker 引入了对 NVIDIA GPU 的原生支持,因此若AI要调用GPU算力的话docker版本也是有要求的,后面博客测试。 当然本篇博客还没设计到GPU的调用,主要Pycharm加Anaconda的方案用习惯了&#…

基于Springboot的社区待就业人员信息管理系统(有报告)。Javaee项目,springboot项目。

演示视频: 基于Springboot的社区待就业人员信息管理系统(有报告)。Javaee项目,springboot项目。 项目介绍: 采用M(model)V(view)C(controller)三…

pdf加水印怎么加?自己原创的PDF资料分享到网络上需要采取一些版权保护的措施,添加水印就是个不错的选择

一,水印的基本概念 水印通常是一种用于标识文件来源、版权信息或防止非法复制的标记。它可以是文字、图形或图像等形式,以半透明或半淡化的方式嵌入到文件中,既不影响文件的正常阅读,又能起到标识和保护的作用。 二,…

mars3d实现禁止地图移动,禁止地图左右平移,但是鼠标可以移动的效果。

new mars3d.layer.GeoJsonLayer({渲染后实现鼠标左键按住不释放拖动时,地图不跟着拖动效果 当前问题: 1.在map初始化,或者是加载效果的时候,整个地球的场景都是一样的。 如果鼠标左键按住不释放,在屏幕上拖动的时候…

设计模式代码实战-责任链模式

1、问题描述 小明所在的公司请假需要在OA系统上发布申请,整个请求流程包括多个处理者,每个处理者负责处理不同范围的请假天数,如果一个处理者不能处理请求,就会将请求传递给下一个处理者,请你实现责任链模式&#xff…

C++:map和set的使用

一、关联式容器介绍 在学习map和set之前,我们接触到的容器有:vector、list、stack、queue、priority_queue、array,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。 关联式容器也是用…

Appian发布最新版本:通过AI流程自动化推动业务发展

Appian公司于2024年4月16日在弗吉尼亚州麦克莱恩宣布推出Appian平台的最新版本。此版本引入了Process HQ,这是一个集流程挖掘和企业AI于一体的系统,结合了Appian的数据平台。Process HQ为企业运营提供前所未有的可见性,支持数据驱动的决策和流…

微信小程序四(全局配置和页面配置页面跳转)

全局配置: 小程序根目录下的 app.json 文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等 tabBar设置:最少两个最多5个 "tabBar": {"list":[{"pagePath": &qu…

【若依】代码生成详细教程(单表、主从表、树形表增删改查)

若依代码生成开发接口 修改代码生成配置一、单表实现增删改查1. 新建数据库表结构2. 新建模块,解决项目依赖3. 启动项目,新建菜单4. 导入数据表,自动生成代码5. 将生成代码粘贴到对应的模块,执行生成的sql(用于生成菜单…

OpenHarmony网络协议通信—nanopb

简介 nanopb是一种小代码量的协议缓冲区实现,适用于任何内存受限的系统。 下载安装 直接在OpenHarmony-SIG仓中搜索nanopb并下载。 使用说明 以OpenHarmony 3.1 Beta的rk3568版本为例 将下载的Nanopb库代码存在以下路径:./third_party/nanopb 修改添…

一键设置个性手机壁纸:苹果手机怎么设置动态壁纸?

在苹果手机上设置动态壁纸是一种让你的手机屏幕更生动、更有趣的方式。无论是流动的水滴、绚丽的光影还是动态的星空,动态壁纸可以为你的手机带来全新的视觉体验。苹果手机怎么设置动态壁纸?在本文中,我们将介绍苹果手机上如何设置动态壁纸的…

李沐-16 PyTorch 神经网络基础【动手学深度学习v2】

注:1. 沐神对应章节视频出处 2.代码使用Jupyter Notebook运行更方便 3.文章笔记出处 一、层和块 层:层(1)接受一组输入, (2)生成相应的输出, (3)由一组可调整…

priority queue优先队列(三)

一、优先队列 优先队列不再遵循先进先出的原则,而是分为两种情况: 最大优先队列,无论入队顺序如何,都是当前最大的元素优先出队。 最小优先队列,无论入队顺序如何,都是当前最小的元素优先出队。 在操作系统中&#xf…

k8s 部署 kube-prometheus监控

一、Prometheus监控部署 1、下载部署文件 # 使用此链接下载后解压即可 wget https://github.com/prometheus-operator/kube-prometheus/archive/refs/heads/release-0.13.zip2、根据k8s集群版本获取不同的kube-prometheus版本部署 https://github.com/prometheus-operator/k…