介绍
在之前的两篇文章中,我们已经介绍了使用 gRPC 创建 RPC 应用的前导知识。我们了解到 gRPC 支持多语言,本文我们介绍在 Golang 语言中怎么使用 gRPC。
准备工作
既然我们要介绍 gRPC 怎么在 Golang 语言中使用,那么我们必须搭建 Golang 开发环境。这部分内容比较简单,本文就不再赘述了,如果有读者朋友对这块内容不清楚,建议阅读 Golang 官网文档。
此外,我们还需要安装接口设计语言 Protocol buffer 的编译器 protoc,我们在之前的文章「Protobuf - 更小、更快、更简单的交互式数据语言」中也已经介绍过 protoc 的安装方法,本文就不再赘述了,如果有需要了解的读者朋友,可以翻阅一下这篇文章。
最后,我们介绍一下 protoc 编译生成 pb 文件需要使用的插件 protoc-gen-go
和 protoc-gen-go-grpc
。插件安装方式,具体如下:
- 执行
go install
命令安装插件
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26 $ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1
- 修改 PATH
$ export PATH="$PATH:$(go env GOPATH)/bin"
完成以上两步之后,我们就可以使用 protoc 编译 .proto
文件,生成 pb 文件了。
03
编写 .proto
文件和生成 pb 文件
在 Golang 语言中使用 gRPC,首先编写 .proto
文件,然后使用 protoc 编译 .proto
文件生成 pb 文件,最后编写剩余的 Golang 代码。
接口设计语言 protobuf,在之前的文章 「Golang 语言 gRPC 使用的接口设计语言 protobuf」 中也已经介绍过了,本文不再赘述,如果有需要了解的读者朋友,可以翻阅一下这篇文章。
示例代码:
syntax = "proto3"; option go_package = "advanced_go/lesson06/proto/greeter"; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }
- 使用 protoc 编译
.proto
文件,生成 pb 文件。
$ protoc --go_out=. --go_opt=paths=source_relative \ --go-grpc_out=. --go-grpc_opt=paths=source_relative \ proto/helloworld.proto
04
编写服务端和客户端 Golang 代码
我们在之前的文章中介绍过 gRPC 是什么,接下来,我们通过示例代码介绍在 Golang 语言中怎么使用 gRPC,本文先来介绍使用 gRPC 的编码流程,限于篇幅,关于 gRPC 的更多使用方法,后续会新开篇文章介绍。
首先使用接口设计语言 protobuf 的编译器 protoc
、protoc-gen-go
和 protoc-gen-go-grpc
插件生成 pb 文件,我们通过查看生成的 pb 文件,可以看到 protoc 为我们自动生成结构体、接口和方法等 Golang 代码。
接下来,我们只需把剩余的 Golang 代码写完就可以了,具体实现如下:
服务端示例代码:
const ( port = ":50051" ) type server struct { pb.UnimplementedGreeterServer } func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { log.Printf("Received: %v", in.GetName()) return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil } func main () { lis, err := net.Listen("tcp", port) if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() pb.RegisterGreeterServer(s, &server{}) log.Printf("server listening at %v", lis.Addr()) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } }
阅读上面这段代码,我们使用 Golang 语言编写了 SayHello 方法,该方法实际上就是 pb 文件中自动生成的 SayHello 方法的具体实现,对应自动生成的 pb 文件 helloworld_grpc.pb.go
中的代码如下:
// UnimplementedGreeterServer must be embedded to have forward compatible implementations. type UnimplementedGreeterServer struct { } func (UnimplementedGreeterServer) SayHello(context.Context, *HelloRequest) (*HelloReply, error) { return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented") }
在 main 函数中,我们使用 grpc 调用 NewServer 函数创建一个服务,然后使用 pb 文件中的 RegisterGreeterServer 函数注册服务,对应自动生成的 pb 文件 helloworld_grpc.pb.go
中的代码如下:
func RegisterGreeterServer(s grpc.ServiceRegistrar, srv GreeterServer) { s.RegisterService(&Greeter_ServiceDesc, srv) }
客户端示例代码:
const( address = ":50051" defaultName = "word" ) func main () { conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock()) if err != nil { log.Fatalf("did not connect: %v", err) } defer conn.Close() c := pb.NewGreeterClient(conn) name := defaultName if len(os.Args) > 1 { name = os.Args[1] } ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name}) if err != nil { log.Fatalf("could not greet: %v", err) } log.Printf("Greeting: %s", r.GetMessage()) }
阅读上面这段代码,我们使用 pb 文件中的 NewGreeterClient 方法创建一个客户端,然后就可以使用创建的客户端直接调用服务端的 SayHello 方法,对应自动生成的 pb 文件 helloworld_grpc.pb.go
中的代码如下:
type GreeterClient interface { SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) } type greeterClient struct { cc grpc.ClientConnInterface } func NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient { return &greeterClient{cc} } func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) { out := new(HelloReply) err := c.cc.Invoke(ctx, "/Greeter/SayHello", in, out, opts...) if err != nil { return nil, err } return out, nil }
编写完服务端和客户端代码,接下来,我们分别启动服务端和客户端,执行结果如下:
go run grpc_server/main.go 2021/09/11 23:02:59 server listening at [::]:50051 2021/09/11 23:03:23 Received: word 2021/09/11 23:03:31 Received: frank go run grpc_client/main.go 2021/09/11 23:03:23 Greeting: Hello word go run grpc_client/main.go frank 2021/09/11 23:03:31 Greeting: Hello frank
05
总结
本文我们介绍在 Golang 语言中怎么使用 gRPC,为了方便读者朋友们理解,文章通过一个简单示例从零到一的实现,介绍了在 Golang 语言中使用 gRPC 的编码流程。
建议读者朋友们阅读完本文,动手敲一遍示例代码,来进一步加深理解。限于篇幅,关于 gRPC 的更多使用方法,我们后续撰文介绍。
编码流程归纳如下:
- 搭建 Golang 开发环境。
- 安装 protobuf 编译器 protoc 和插件
protoc-gen-go
、protoc-gen-go-grpc
,设置环境变量。 - 初始化项目
go mod init
。 - 编写 protobuf,生成 pb 文件,执行
go mod tidy
整理依赖包。 - 编写剩余 Golang 代码。
推荐阅读:
参考资料:
https://golang.org/doc/install