保姆级教程告诉你 grpc-go 的服务端客户端实现
以下示例来自于个人整理,大佬轻喷。
示例的项目目录:
1.proto环境准备
这里的环境准备主要就是以下三点:
- protoc
- protoc-gen-go
- protoc-gen-go-grpc
- go三方库 grpc
接下来是相关插件的安装。
protoc
根据操作系统型号,下载安装好对应版本的 protobuf 应用:
https://github.com/google/protobuf/releases
需要将 protobuf 执行文件所在的目录添加到环境变量 $PATH
当中.
安装完成后,可以通过查看 protobuf 版本指令,校验安装是否成功
protoc --version
protoc-gen-go
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
该插件的作用是,能够基于 .proto
文件一键生成 _pb.go
文件,对应内容为通信请求/响应参数
的对象模型.
go install
指令默认会将插件安装到 $GOPATH/bin
目录下. 需要确保 $GOPATH/bin
路径有被添加到环境路径 $PATH
当中.
安装完成后,可以通过查看插件版本指令,校验安装是否成功
protoc-gen-go --version
protoc-gen-go-grpc
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
该插件的作用是,能够基于 .proto
文件生成 _grpc.pb.go
,对应内容为通信服务框架
代码.
安装完成后,可以通过查看插件版本指令,校验安装是否成功
protoc-gen-go-grpc --version
go三方库 grpc
# 安装三方库
go get google.golang.org/grpc@latest
2.编写 IDL
auth.proto
syntax = "proto3";
option go_package = "."; // 指定生成的go代码在你项目中的导入路径
package pb; // 包名
// 定义service
service AuthService {
rpc Auth (AuthRequest) returns (AuthResponse) {}
}
// 定义请求参数
message AuthRequest {
string name = 1;
string password = 2;
}
// 定义响应参数
message AuthResponse {
string reply = 1;
}
math.proto
syntax = "proto3";
option go_package = "."; // 指定生成的go代码在你项目中的导入路径
package pb; // 包名
// 定义service
service MathService {
rpc Sum (MathRequest) returns (MathResponse) {}
rpc Multi (MathRequest) returns (MathResponse) {}
}
// 定义请求参数
message MathRequest {
int64 num1 = 1;
int64 num2 = 2;
}
// 定义响应参数
message MathResponse {
int64 reply = 1;
}
关于各参数的含义请自行搜索。
3.生成pb.go, grpc_pb.go
进入 pb
目录,生成 出入参
模型(pb.go
)及 服务端框架
(grpc.pb.go
)
cd pb
protoc --go_out=. --go-grpc_out=. auth.proto
protoc --go_out=. --go-grpc_out=. math.proto
可以观察到生成的如下文件:
xxx.pb.go
xxx.grpc.pb.go
新建一个 proto 目录,将上面的文件移入该文件夹。
4.实现服务端
auth.go
package server
import (
"context"
"errors"
authpb "go-grpc-demo/proto"
)
type AuthService struct {
authpb.UnimplementedAuthServiceServer
}
func (a *AuthService) Auth(c context.Context, req *authpb.AuthRequest) (*authpb.AuthResponse, error) {
if req.Name != "admin" && req.Password != "123456" {
return &authpb.AuthResponse{Reply: "Wrong auth params"}, errors.New("Wrong auth params")
}
return &authpb.AuthResponse{Reply: "Auth pass"}, nil
}
math.go
package server
import (
"context"
mathpb "go-grpc-demo/proto"
"log"
)
type MathService struct {
mathpb.UnimplementedMathServiceServer
}
func (m *MathService) Sum(c context.Context, req *mathpb.MathRequest) (*mathpb.MathResponse, error) {
sum := req.Num1 + req.Num2
log.Printf("num1: %d, num2: %d, sum: %d\n", req.Num1, req.Num2, sum)
return &mathpb.MathResponse{Reply: sum}, nil
}
func (m *MathService) Multi(c context.Context, req *mathpb.MathRequest) (*mathpb.MathResponse, error) {
reply := req.Num1 * req.Num2
log.Printf("num1: %d, num2: %d, reply: %d\n", req.Num1, req.Num2, reply)
return &mathpb.MathResponse{Reply: reply}, nil
}
server.go(main)
package main
import (
pb "go-grpc-demo/proto"
"go-grpc-demo/server"
"google.golang.org/grpc"
"log"
"net"
)
const PORT = ":50052"
func main() {
// 1.创建监听器
lis, err := net.Listen("tcp", PORT)
if err != nil {
panic(err)
}
// 2.创建grpc server
srv := grpc.NewServer()
// 3.注册服务
log.Println("正在注册服务...")
pb.RegisterMathServiceServer(srv, &server.MathService{})
pb.RegisterAuthServiceServer(srv, &server.AuthService{})
// 4.启动服务
log.Println("即将启动服务...")
err = srv.Serve(lis)
if err != nil {
panic(err)
}
}
5.实现客户端
client.go
package main
import (
"context"
pb "go-grpc-demo/proto"
"google.golang.org/grpc"
"log"
)
func main() {
// 1.创建连接器
conn, err := grpc.Dial(":50052", grpc.WithInsecure())
if err != nil {
panic(err)
}
defer conn.Close()
// 2.创建对应 grpc 客户端
client := pb.NewAuthServiceClient(conn)
// 3.根据函数调用发送 grpc 请求
resp, err := client.Auth(context.Background(), &pb.AuthRequest{Name: "admin", Password: "123456"})
if err != nil {
panic(err)
}
log.Printf("auth grpc response: %v\n", resp.Reply)
}
6.测试
先启动 server
,然后运行 client
: