您现在的位置是:首页 >学无止境 >基于protobuf构建grpc服务网站首页学无止境
基于protobuf构建grpc服务
一、protobuf介绍
protobuf是谷歌开源的一种数据格式,适合高性能,对响应速度有要求的数据传输场景。因为profobuf是二进制数据格式,需要编码和解码。数据本身不具有可读性。因此只能反序列化之后得到真正可读的数据。
优势:
-
序列化后体积相比Json和XML很小,适合网络传输
-
支持跨平台多语言
-
消息格式升级和兼容性还不错
-
序列化反序列化速度很快
二、安装
第一步:下载通用编译器
地址:Releases · protocolbuffers/protobuf · GitHub
根据不同的操作系统,下载不同的包,我是windows电脑,解压出来是protoc.exe
第二步:配置环境变量
第三步:安装go专用的protoc的生成器
go get github.com/golang/protobuf/protoc-gen-go
安装后会在GOPATH
目录下生成可执行文件,protobuf的编译器插件protoc-gen-go
,执行protoc
命令会自动调用这个插件
第四步、使用protobuf
-
定义了一种源文件,扩展名为
.proto
,使用这种源文件,可以定义存储类的内容(消息类型) -
protobuf有自己的编译器
protoc
,可以将.proto
编译成对应语言的文件,就可以进行使用了
四、proto样例
// 指定的当前proto语法的版本,有2和3
syntax = "proto3";
//option go_package = "path;name"; ath 表示生成的go文件的存放地址,会自动生成目录的
// name 表示生成的go文件所属的包名
option go_package="../service";
// 指定等会文件生成出来的package
package service;
message User {
string username = 1;
int32 age = 2;
}
运行protoc命令编译成go中间文件
# 编译user.proto之后输出到service文件夹
protoc --go_out=../service user.proto
五、构建rpc服务
5.1 项目结构
5.2、编写protobuf文件
// 这个就是protobuf的中间文件
// 指定的当前proto语法的版本,有2和3
syntax = "proto3";
option go_package="../service";
// 指定等会文件生成出来的package
package service;
// 定义request model
message ProductRequest{
int32 prod_id = 1; // 1代表顺序
}
// 定义response model
message ProductResponse{
int32 prod_stock = 1; // 1代表顺序
}
// 定义服务主体
service ProdService{
// 定义方法
rpc GetProductStock(ProductRequest) returns(ProductResponse);
}
5.3 利用proto生成
protoc --go_out=plugins=grpc:./ .product.proto
值得注意的是,上面的生成命令中需要指定 grpc ,这样我们在文件中定义的 service 部分会生成对应的接口,我们只需要在服务端中实现这个接口即可。
5.4 服务端代码
接口实现:
启动方法代码
import "google.golang.org/grpc"
func main() {
server := grpc.NewServer()
service.RegisterProdServiceServer(server,service.ProductService)
listener, err := net.Listen("tcp", ":8002")
if err != nil {
log.Fatal("服务监听端口失败", err)
}
_ = server.Serve(listener)
}
5.4 客户端代码
新建client目录,把上述生成的product.pb.go copy过来,因为生成的时候会把服务端和客户端一并生成。
func main() {
// 1. 新建连接,端口是服务端开放的8002端口
// 没有证书会报错
conn, err := grpc.Dial(":8002", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatal(err)
}
// 退出时关闭链接
defer conn.Close()
// 2. 调用Product.pb.go中的NewProdServiceClient方法
productServiceClient := service.NewProdServiceClient(conn)
// 3. 直接像调用本地方法一样调用GetProductStock方法
resp, err := productServiceClient.GetProductStock(context.Background(), &service.ProductRequest{ProdId: 233})
if err != nil {
log.Fatal("调用gRPC方法错误: ", err)
}
fmt.Println("调用gRPC方法成功,ProdStock = ", resp.ProdStock)
}