1 准备工具
对于go语言项目怎么用protobuf,官方有完整的资料说明,地址 Protocol Buffer Basics: Go | Protocol Buffers Documentation
1.1 获取编译工具(protoc)
首先需要一个编译工具,对应的就是一个可执行文件比如protoc.exe,protoc运行是把.proto文件转换为 c++统一格式的内存数据, 然后由语言插件把内存数据转换为各自语言的代码文件,比如go语言就提供了protoc-gen-go插件。
要获取protoc,去官网下载zip包解压即可使用,windows、linux版本都有。参照protocol-buffers官网的下载说明, 要去github上release page下载需要的版本,地址看上面官网获取。
windows上,我们下载得到protoc-21.9-win64.zip,解压后把bin目录下的protoc.exe放到PATH下。我选择把可执行文件 复制到已经配置好的PATH路径下,比如C:\Program Files\Go\bin下。
1.2 获取编译工具go语言的插件
protoc-gen-go语言插件用go get就能下载,可执行文件会被放到GOPATH/bin下。
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
有了protoc和protoc-gen-go, 使用protoc命令,就能把一个.proto文件转换为一个 .go文件。
protoc --go_out=. *.proto
1.3 获取编译工具的grpc插件
对于旧版本的protoc工具,只要安装完了protoc工具,就能使用protoc命令,把一个定义了grpc的.protoc文件转换为.go文件, 命令要用protoc --go_out=plugins=grpc:. hello.proto。
但是新版本google.golang.org/protobuf/ 不再支持gRPC服务定义,如果想要生成grpc代码需要使用新插件 protoc-gen-go-grpc。
安装插件,也是用go get下载,可执行文件会被放到GOPATH/bin下。
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
使用命令
protoc --go-grpc_out=. *.proto
2 一个demo
写一个article.proto文件,在路径 use_grpc/v1/article.proto
用工具生成article.pb.go和article_grpc.pb.go, 在目录 use_grpc/v1/proto
grpc的server服务,在目录 /use_grpc/v1/server
grpc的client服务,在目录 /use_grpc/v1/client
2.1 proto转pb
先按照protobuf官方使用要求,安装protoc工具,安装protoc-gen-go插件,安装protoc-gen-go-grpc插件。
1、编写proto文件, 这里的例子是article.proto。
//proto3标准
syntax = "proto3";
option go_package = "./proto";
package Article;
// 定义rpc接口
service Article {
rpc ArticleAdd (AddRequest) returns (AddResponse) {}
}
//AddRequest协议内容
message AddResponse {
string data = 1;
}
//AddRequest协议内容
message AddRequest {
string name = 1;
string content = 2;
}
2、然后进入项目目录 /use_grpc/v1下,即article.proto所在目录下,执行如下两个命令
protoc --go_out=. *.proto
protoc --go-grpc_out=. *.proto
3、会在项目目录下生成一个proto目录,里面得到两个文件
- article.pb.go
- article_grpc.pb.go
2.2 实现server
我们需要创建一个struct,它要实现article_grpc.pb.go文件中定义的接口ArticleServer,具体的方式,就是我们的业务逻辑实现。
package main
import (
"context"
"google.golang.org/grpc"
"log"
"net"
"swwgo/basic/use_grpc/v1/proto"
)
func main() {
lis, err := net.Listen("tcp", "0.0.0.0:1001")
if err != nil {
log.Fatalln("failed to listen")
}
grpcServer := grpc.NewServer()
proto.RegisterArticleServer(grpcServer, new(ArticleServer))
grpcServer.Serve(lis)
}
type ArticleServer struct {
proto.UnimplementedArticleServer
}
func (s ArticleServer) ArticleAdd(ctx context.Context, request *proto.AddRequest) (*proto.AddResponse, error) {
res := &proto.AddResponse{
Data: request.Name + " " + request.Content,
}
return res, nil
}
2.3 实现client
实现client非常简单,直接使用文件中定义的NewArticleClient()就可以。
package main
import (
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"log"
"swwgo/basic/use_grpc/v1/proto"
"time"
)
func main() {
conn, err := grpc.Dial(":1001", grpc.WithInsecure())
if err != nil {
log.Fatalln("did not connect")
}
defer conn.Close()
c := proto.NewArticleClient(conn)
// 可以传递一些meta信息
paramCtx := context.Background()
pairs := metadata.Pairs("k1", "v1", "k2", "v2")
outgoingContext := metadata.NewOutgoingContext(paramCtx, pairs)
ctx, cancel := context.WithTimeout(outgoingContext, time.Second)
defer cancel()
res, err := c.ArticleAdd(ctx, &proto.AddRequest{Name: "xiaoming", Content: "beijing"})
if err != nil {
log.Fatalf("could not add article %v", err)
}
log.Printf("response: %s", res.Data)
}