Golang 语言 gRPC 怎么使用?

简介: Golang 语言 gRPC 怎么使用?

介绍

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

准备工作

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

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

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

  1. 执行 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
  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;
}
  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-goprotoc-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 代码。

推荐阅读:

参考资料:

https://golang.org/doc/install 

https://developers.google.com/protocol-buffers/docs/proto3 

https://grpc.io/docs/languages/go/ 

目录
相关文章
|
4月前
|
Go
Golang语言之管道channel快速入门篇
这篇文章是关于Go语言中管道(channel)的快速入门教程,涵盖了管道的基本使用、有缓冲和无缓冲管道的区别、管道的关闭、遍历、协程和管道的协同工作、单向通道的使用以及select多路复用的详细案例和解释。
146 4
Golang语言之管道channel快速入门篇
|
4月前
|
Go
Golang语言文件操作快速入门篇
这篇文章是关于Go语言文件操作快速入门的教程,涵盖了文件的读取、写入、复制操作以及使用标准库中的ioutil、bufio、os等包进行文件操作的详细案例。
72 4
Golang语言文件操作快速入门篇
|
4月前
|
Go
Golang语言之gRPC程序设计示例
这篇文章是关于Golang语言使用gRPC进行程序设计的详细教程,涵盖了RPC协议的介绍、gRPC环境的搭建、Protocol Buffers的使用、gRPC服务的编写和通信示例。
120 3
Golang语言之gRPC程序设计示例
|
4月前
|
安全 Go
Golang语言goroutine协程并发安全及锁机制
这篇文章是关于Go语言中多协程操作同一数据问题、互斥锁Mutex和读写互斥锁RWMutex的详细介绍及使用案例,涵盖了如何使用这些同步原语来解决并发访问共享资源时的数据安全问题。
101 4
|
4月前
|
Go 调度
Golang语言goroutine协程篇
这篇文章是关于Go语言goroutine协程的详细教程,涵盖了并发编程的常见术语、goroutine的创建和调度、使用sync.WaitGroup控制协程退出以及如何通过GOMAXPROCS设置程序并发时占用的CPU逻辑核心数。
82 4
Golang语言goroutine协程篇
|
4月前
|
Prometheus Cloud Native Go
Golang语言之Prometheus的日志模块使用案例
这篇文章是关于如何在Golang语言项目中使用Prometheus的日志模块的案例,包括源代码编写、编译和测试步骤。
82 3
Golang语言之Prometheus的日志模块使用案例
|
3月前
|
前端开发 中间件 Go
实践Golang语言N层应用架构
【10月更文挑战第2天】本文介绍了如何在Go语言中使用Gin框架实现N层体系结构,借鉴了J2EE平台的多层分布式应用程序模型。文章首先概述了N层体系结构的基本概念,接着详细列出了Go语言中对应的构件名称,包括前端框架(如Vue.js、React)、Gin的处理函数和中间件、依赖注入和配置管理、会话管理和ORM库(如gorm或ent)。最后,提供了具体的代码示例,展示了如何实现HTTP请求处理、会话管理和数据库操作。
48 0
|
4月前
|
JSON Go 数据格式
Golang语言结构体链式编程与JSON序列化
这篇文章是关于Go语言中结构体链式编程与JSON序列化的教程,详细介绍了JSON格式的基本概念、结构体的序列化与反序列化、结构体标签的使用以及如何实现链式编程。
48 4
|
4月前
|
Go
Golang语言结构体(struct)面向对象编程进阶篇(封装,继承和多态)
这篇文章是关于Go语言中结构体(struct)面向对象编程进阶篇的教程,涵盖了Go语言如何实现封装、继承和多态,以及结构体内存布局的相关概念和案例。
197 4
|
4月前
|
Go
Golang语言基础之接口(interface)及类型断言
这篇文章是关于Go语言中接口(interface)及类型断言的详细教程,涵盖了接口的概念、定义、实现、使用注意事项以及类型断言的多种场景和方法。
44 4