go实现gPRC服务
go实现gRPC服务
本文介绍如何使用go语言搭建简单的gRPC服务,内容比较基础,记录自己的踩坑过程。
1. 背景知识
gRPC是一种高效的远程过程调用(RPC)框架,用于不同计算机之间的通信和远程服务调用。gRPC的目标是让客户端向调用本地方法一样调用其他机器上的服务端应用程序提供的方法,能够帮助开发者更方便高效的构建分布式应用程序和服务。
protocol buffers是实现gRPC服务的基础,gRPC使用protocol buffers提供了一种简洁而强大的接口定义语言(IDL),gRPC通过.proto
文件定义服务和消息类型,由于protocol buffers是一种用于序列化结构化数据的与语言无关的格式,因此,使用.proto
文件定义的服务可以使用任意语言编写业务逻辑,从而实现该服务。
2. gRPC服务实现过程
-
实现一个gRPC服务主要包括以下步骤:
-
定义服务接口:定义服务,服务的方法,接收和返回的消息类型
-
编译proto文件:使用protoc编译器编译生成服务相关的go文件
-
开发业务逻辑:实现proto中定义的方法
-
创建gRPC服务:创建gRPC服务器,并绑定业务逻辑
3. 基础环境配置
3.1 go get配置代理
golang默认的代理 https://proxy.golang.org 在国内下载速度很慢,使用以下命令设置golang代理为 https://goproxy.cn
go env -w GOPROXY=https://goproxy.cn,direct
3.2. protoc安装
protoc是一款命令行工具,用于自动根据proto后缀的protobuf文件生成相关的go文件,从以下github仓库中下载可执行文件
将下载完成的可执行文件放入%GOPATH%/bin
目录下(也可以放入其他目录并添加环境变量)
在命令行中运行 protoc --version
成功显示版本号则说明安装成功
3.3 protocol compiler plugin安装
使用一下命令安装相关的插件,go install命令会下载依赖源码并进行编译,编译完成的可执行文件位于GOPATH下。
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
安装完成后,能够在%GOPATH%/bin目录下找到刚刚安装完成的插件可执行文件
后续的自动生成proto代码时,会调用到当前目录下的可执行文件。一般go安装时会自动将GOPATH添加到环境变量,如果没有,则需要手动添加。
2. 定义服务
2.1 编写proto代码
定义服务接口、接收和响应的消息类型均在.proto
文件中定义,以下代码中,定义了一个服务Greeter
,服务中定义了一个rpc方法SayHello
,该方法接收一个HelloRequest类型的消息,并返回一个HelloReply类型的响应。
syntax = "proto3"; // 指定protoc版本
option go_package = "gRPC_demo/protos/helloworld"; // 指定自动生成go代码时的包名
package helloworld; // 指定包名,防止命名冲突
// 定义Greeter服务
service Greeter {
// 定义SayHello方法
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// 定义HelloRequest消息,消息中包括一个string类型的name字段
message HelloRequest {
string name = 1; // 1代表该字段的排序编号,如该消息还有第2个字段pass,则定义为 string pass = 2;
}
// 定义HelloReply消息,消息中包括一个string类型的message字段
message HelloReply {
string message = 1;
}
}
2.2. 编译.proto
文件
protocol buffers是一种与语言无关的接口定义语言,在使用不同的语言实现时,都可以通过对应的插件将.proto
定义代码编译成对应语言的代码。为了适应开发过程中.proto
文件的频繁变更,可以将编译命令写入gen.bat
文件,方便后续发生变更时快速重新生成代码,注意将.proto
文件和.bat
文件放在同一层目录,并cd到bat文件所在目录执行bat文件,防止代码生成到其他目录造成目录结构混乱
// gen.bat
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go grpc_opt=paths=source_relative .helloworld.proto
执行bat文件后,将自动生成了两个go文件,**.grpc.pb.go
和**.pb.go
,它们包含的内容如下:
-
**.grpc.pb.go
:该文件包含gRPC服务端和客户端的代码框架,后续将基于该框架编写服务的业务逻辑,实现.proto
文件中定义的服务。 -
**.pb.go
: 该文件保险消息类型的定义和相关的序列化/反序列化方法,通信过程中,将调用这些方法对消息进行处理。
2.3 同步依赖
生成的代码由于依赖未同步,可能存在大范围飘红,在命令行执行go mod tidy自动同步依赖即可
3. 实现业务逻辑
打开helloworld_grpc.pb.go
,可以看到SayHello方法定义如下,会返回一个SayHello方法没有实现的错误,我们可以在SayHello中编写业务逻辑,但是由于helloworld_grpc.pb.go是自动生成的代码,在后续发生变更时,重新编译会覆盖我们编写的业务逻辑代码,因此强烈不建议在helloworld_grpc.pb.go
中直接编写业务逻辑代码。
func (UnimplementedGreeterServer) SayHello(context.Context, *HelloRequest) (*HelloReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented")
} nil
}
推荐的方法是在项目根目录下创建一个services/helloworld目录,在目录中创建一个helloworld.go,新建一个结构体Server,继承UnimplementedGreeterServer结构体中的所有方法,并重写UnimplementedGreeterServer.SayHello方法,实现业务逻辑。
package helloworld
import (
"context"
pb "gRPC_demo/protos/helloworld"
"log"
)
// 创建Server结构体,将SayHello方法注册为它的成员函数
type Server struct {
pb.UnimplementedGreeterServer // Server结构体继承了pb.UnimplementedGreeterServer结构体的所有方法
}
// 重写pb.GreeterServer.SayHello方法,实现业务逻辑
func (s *Server) SayHello(ctx context.Context, hellorequest *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Received message from %v", hellorequest.GetName())
return &pb.HelloReply{Message: "Hello " + hellorequest.GetName()}, nil
}
项目目录结构如下:
4. 编写main函数
在项目根目录编写以下main函数,新建一个gRPC服务,将gRPC服务和我们实现的Server结构体中的业务逻辑绑定到Greeter服务上,并开启监听。
package main
import (
"fmt"
pb "gRPC_demo/protos/helloworld"
"gRPC_demo/services/helloworld"
"log"
"net"
"google.golang.org/grpc"
)
func main() {
// 绑定地址和端口
grpcAddress := "0.0.0.0"
grpcPort := 8090
lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", grpcAddress, grpcPort))
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
// 初始化gRPC服务
s := grpc.NewServer()
// 将gRPC服务和自定义的业务逻辑注册到Greeter服务中
pb.RegisterGreeterServer(s, &helloworld.Server{})
log.Printf("serving gRPC on %v", lis.Addr())
// 将gRPC服务绑定在上面创建的tcp端口上,并开启监听
err = s.Serve(lis)
if err != nil {
log.Fatalf("启动gRPC服务失败(%v)", err)
}
}
5. 运行gRPC服务
使用一下命令启动gRPC服务
go run main.go
7. 调用测试
将proto文件导入apifox后调用SayHello方法
服务端也打印了调用的日志信息
以上是go实现gRPC服务的简单示例,如有疏漏,欢迎评论区指正。
下节预告: 下一节将讲解如何使用grpc-gateway实现http协议访问grpc服务。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战