Golang 语言 gRPC 怎么使用?

2021年9月12日 321点热度 0人点赞 0条评论

大家好,我是 frank。
欢迎大家点击标题下方蓝色文字「Golang 语言开发栈」关注公众号。
设为星标,第一时间接收推送文章。
文末扫码,大家一起学 Golang 语言。

01 

介绍

在之前的两篇文章中,我们已经介绍了使用 gRPC 创建 RPC 应用的前导知识。我们了解到 gRPC 支持多语言,本文我们介绍在 Golang 语言中怎么使用 gRPC。

02 

准备工作

既然我们要介绍 gRPC 怎么在 Golang 语言中使用,那么我们必须搭建 Golang 开发环境。这部分内容比较简单,本文就不再赘述了,如果有读者朋友对这块内容不清楚,建议阅读 Golang 官网文档。

此外,我们还需要安装接口设计语言 Protocol buffer 的编译器 protoc,我们在之前的文章「Protobuf - 更小、更快、更简单的交互式数据语言」中也已经介绍过 protoc 的安装方法,本文就不再赘述了,如果有需要了解的读者朋友,可以翻阅一下这篇文章。

最后,我们介绍一下 protoc 编译生成 pb 文件需要使用的插件 protoc-gen-go 和 protoc-gen-go-grpc。插件安装方式,具体如下:

  1. 执行 go install 命令安装插件
$ go install google.golang.org/protobuf/cmd/[email protected]
$ go install google.golang.org/grpc/cmd/[email protected]
  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」 中也已经介绍过了,本文不再赘述,如果有需要了解的读者朋友,可以翻阅一下这篇文章。

示例代码:

  1. 编写 .proto 文件。
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;
}
  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 的编译器 protocprotoc-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 的更多使用方法,我们后续撰文介绍。

编码流程归纳如下:

  1. 搭建 Golang 开发环境。
  2. 安装 protobuf 编译器 protoc 和插件 protoc-gen-goprotoc-gen-go-grpc,设置环境变量。
  3. 初始化项目 go mod init
  4. 编写 protobuf,生成 pb 文件,执行 go mod tidy 整理依赖包。
  5. 编写剩余 Golang 代码。

推荐阅读:

Golang 语言中的 defer 怎么使用?

Golang 语言怎么使用 net/http 标准库开发 http 应用?

Golang 语言中怎么拦截系统信号和优雅退出 http server?

Golang 语言中 kafka 客户端库 sarama

Golang 语言中 Context 的使用方式

参考资料:
https://golang.org/doc/install 
https://developers.google.com/protocol-buffers/docs/proto3 
https://grpc.io/docs/languages/go/ 

图片

扫描二维码或回复「微信群」,加入微信群

图片

点「赞」和「在看」是最大的支持?

图片

?更多精彩内容,请点击阅读原文

45500Golang 语言 gRPC 怎么使用?

这个人很懒,什么都没留下

文章评论