【GoWeb框架初探——GRPC】

server/2024/9/23 10:48:08/

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
go">package mainimport ("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请求,等待同步响应,得到回调后返回响应结果
  • 输出响应结果
go">package mainimport ("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

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

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认证

实现接口方法:

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

6.1 客户端附带信息

go">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 服务端处理信息

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

go">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 stringvar appKey stringif 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.ppmy.cn/server/11381.html

相关文章

微服务中Dubbo通俗易懂讲解及代码实现

当你在微服务架构中需要不同服务之间进行远程通信时,Dubbo是一个优秀的选择。Dubbo是一个高性能的Java RPC框架,它提供了服务注册、发现、调用、负载均衡等功能,使得微服务之间的通信变得简单而高效。 让我们来看一下Dubbo的通俗易懂的解释和…

TypeScript 泛型

泛型 介绍 软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。 在像C#和Java这样的语言中&…

Expiring 3623 record(s) for 2:xxx ms has passed since batch

Expiring 3623 record(s) for 2:xxx ms has passed since batch 报错大意为:生产发送批次已经创建,但是已经过去120000ms,仍然没有发送,消息过期 (当kafka服务器磁盘空间不足时,也会报此错误。清空磁盘空间&#xff0…

Excel中将单元格格式改成文本后,为何要双击数字才会改变?

将大批量的数值型数字转换成文本型数字,当然不能一个一个的去双击做转换了。以下说说有哪个可以将数值型数字转换成文本型数字的方法。 一、转换方法 方法1.数据分列功能 选中数据后,点击数据选项卡,分列, 分列向导的第一步和…

复现SMO算法:理解SVM、SMO和高斯核【一、了解相关概念】

任务要求 复现带有高斯核的SMO算法。在LIBSVM中找到一个包含超过1000条数据的数据集。在保持超参数一致的情况下,确保自己实现的模型的精度与LIBSVM相比,相差不超过1%。 复现SMO算法:理解SVM、SMO和高斯核 在这篇博客中,我将深…

界面组件DevExpress WinForms v23.2 - 数据展示、UI模板功能全新升级

DevExpress WinForms拥有180组件和UI库,能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜…

孩子进入叛逆期,最好的教育方式

叛逆期是孩子成长中普遍经历的阶段,这个时期的孩子容易表现出情绪不稳定,抗拒父母的教育和管束。当家长遇到孩子的叛逆期时,又该怎么去做呢?以下几个技巧帮你面对青春期孩子的叛逆问题。 1、当孩子进入叛逆期时,他们可…

K8s: 控制器之StatefulSets对象

StatefulSet 1 ) 概述 Stateful,也就是有状态应用,微服务无状态是一个理想的这么一个环境有些应用是有状态的,比如这个web服务器,它只能运行在一台server上因为它要访问一些持久化的存储比如说 mysql 它就是一个典型的有状态的应…