[TOC]
环境详情
- golang 1.18
- macOS Big Sur
- protobuf 3
基本原理
整个RPC过程就是:
- 客户端 发送 数据(以字节流的形式)
- 服务端接管,并解析。 依据约定晓得要晓得执行什么。而后把后果返回客户端
RPC就是把——
- 上述过程封装下,使其操作更加优化
- 应用一些大家都认可的协定 使其规范化
那么——GRPC框架中采纳了protobuf作为这个过程中消息传递的数据结构。
什么是 Protobuf
Protobuf是Protocol Buffers的简称,它是Google公司开发的一种数据描述语言,用于形容一种轻便高效的结构化数据存储格局,并于2008年对外开源。Protobuf能够用于结构化数据串行化,或者说序列化。它的设计十分实用于在网络通讯中的数据载体,很适宜做数据存储或 RPC 数据交换格局,它序列化进去的数据量少再加上以 K-V 的形式来存储数据,对音讯的版本兼容性十分强,可用于通信协定、数据存储等畛域的语言无关、平台无关、可扩大的序列化构造数据格式。开发者能够通过Protobuf附带的工具生成代码并实现将结构化数据序列化的性能。
本教程将在接下来的内容中形容 .proto 文件的语法以及如何通过 .proto 文件生成数据拜访类和 grpc 服务类,并以此为根底搭建繁难的 grpc 服务端开发环境。
工具装置
新建工程,抉择 go modules,配置 GOPROXY 等操作不再赘述;
- 下载grpc依赖
go get -u google.golang.org/grpc@v1.51.0
- brew 装置 protocol
brew install protobuf
装置后能够执行命令protoc,作为protocol编译器应用,可能通过两头文件 .proto 转译成各种语言的grpc文件
brew install protoc-gen-go
转译两头文件成go文件的插件
brew install protoc-gen-go-grpc
转译两头文件成go-grpc文件的插件。
留神:如果装置失败那可能是依赖装置失败,间接brew intall 装置依赖即可。
至此,工具和依赖装置结束,接下来将构建工程。
环境搭建
工程 go-rpc-server 构造:
.
├── client.go ——用于编写客户端测试
├── go.mod
├── go.sum
├── main.go ——服务端的启动
├── pbfiles ——该目录用于搁置原始proto文件
│ └── Prod.proto
├── services ——该目录用于搁置转译出的go文件
首先新建 .proto 文件,该示例中演示用于展现商品库存的 API,因而取名为 Prod.proto ;
编辑有如下内容 :
syntax="proto3";option go_package ="go-rpc-server/services"; //相对路径 和protoc的flag go_out拼接//package services; //该选项配置后 客户端申请须要多加上services.的门路message ProdRequest { int32 prod_id =1; //传入的商品ID}message ProdResponse{ int32 prod_stock=1;//商品库存}//这里的内容其实能够独立配置一个.proto文件,因为 rpc 服务类的文件会独立于数据拜访类service ProdService { rpc GetProdStock (ProdRequest) returns (ProdResponse);}
文档参考 Protocol Buffer Basics: Go
随后通过protoc生成——
1.数据拜访类
protoc --go_out=./../ pbfiles/Prod.proto
2.rpc服务类
protoc --go-grpc_out=./../ pbfiles/Prod.proto
若报错
只须要在proto文件中退出
option go_package ="go-rpc-server/services";
指定两头文件生成go文件的门路即可。
编写服务类的实现
值得一提的是从某个版本开始,服务类的实现接口产生了以下变动:
type ProdServiceServer interface { GetProdStock(context.Context, *ProdRequest) (*ProdResponse, error) mustEmbedUnimplementedProdServiceServer() //这里是新增的}
并且在生成的 grpc 服务类中有——
type UnimplementedProdServiceServer struct {}func (UnimplementedProdServiceServer) GetProdStock(context.Context, *ProdRequest) (*ProdResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetProdStock not implemented")}func (UnimplementedProdServiceServer) mustEmbedUnimplementedProdServiceServer() {}
实现了上述接口;官网举荐咱们在实现服务类时,嵌套该构造体。
因而有以下实现:
type ProdService struct { UnimplementedProdServiceServer}func (ps *ProdService) GetProdStock(context.Context, *ProdRequest) (*ProdResponse, error) { return &ProdResponse{ProdStock: 233}, nil}
接口返回了咱们的 mock 数据;
启动服务
编写 main 函数,通过 net 包进行监听, 执行 go run main.go
func main() { rpcServer := grpc.NewServer() services.RegisterProdServiceServer(rpcServer, new(services.ProdService)) lis, _ := net.Listen("tcp", ":8087") rpcServer.Serve(lis)}
至此,咱们的 grpc 服务端环境搭建结束。
客户端测试
多的不说,间接上客户端代码:
func main() { cli, _ := grpc.DialContext(context.Background(), "localhost:8087", grpc.WithTransportCredentials(insecure.NewCredentials()), ) req := &services.ProdRequest{} rsp := &services.ProdResponse{} err := cli.Invoke(context.Background(), "/ProdService/GetProdStock", req, rsp) if err != nil { log.Fatal(err) } fmt.Println(rsp.ProdStock)}
执行go run client.go
,于是有:
搞定!
本文由博客一文多发平台 OpenWrite 公布!