您现在的位置是:首页 >学无止境 >go grpc实战网站首页学无止境
go grpc实战
简介go grpc实战
go rpc实战
什么是rpc以及rpc的原理就不加以阐述了,wiki-rpc对其进行了说明。本文 以登录过程为例,使用go作为开发语言,使用grpc库实现了登录接口。具体过程及代码如下所示。
环境准备
- 在
app
的同级目录创建appGoPath
目录,在goland
的File
->Settings
中配置GOPATH
为appGoPath
目录所在路径,然后执行下列命令准备grpc环境go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28 go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
- 创建目录:
app/cmd/componentTest/pb
,存放登录相关的rpc相关的文件 pb
目录下创建登录服务的grpc服务文件login.proto
syntax = "proto3"; package login; option go_package = "../pb"; message LoginRequest{ string username=1; string password=2; } message LoginResponse{ int32 code=1; string msg=2; } service LoginService{ rpc Login(LoginRequest)returns(LoginResponse); }
pb
目录下创建build.sh
文件,增加如下内容protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=require_unimplemented_servers=false:. --go-grpc_opt=paths=source_relative login.proto
require_unimplemented_servers=false
作用: 在LoginServiceServer中不生成mustEmbedUnimplementedLoginServiceServer接口- 在
pb
目录所在路径下执行build.sh
文件,会自动生成以下两个文件login.pb.go
login_grpc.pb.go
- 生成的上述两个文件在goland中提示
Cannot resolve symbol 'protobuf'
,使用goland
的Sync dependency of
机制进行同步即可 - 在
app/cmd/componentTest
目录下创建test
目录,创建rpc_login_test.go
文件,添加代码如下:package test import ( "context" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "log" "app/cmd/componentTest/pb" "net" "os" "os/signal" "syscall" "testing" "time" ) type LoginServiceServerImpl struct{} func (l LoginServiceServerImpl) Login(ctx context.Context, request *pb.LoginRequest) (*pb.LoginResponse, error) { username := request.Username password := request.Password if username == "leebai" && password == "123456" { return &pb.LoginResponse{ Code: 200, Msg: "success", }, nil } else { return &pb.LoginResponse{ Code: 201, Msg: "fail", }, nil } } func StartRpcServer() { s := grpc.NewServer() pb.RegisterLoginServiceServer(s, new(LoginServiceServerImpl)) port := ":8081" listener, err := net.Listen("tcp", port) if err != nil { log.Printf("listen port %s failed,err=%v ", port, err) } s.Serve(listener) } // TestRpcLoginService 启动Rpc登录服务 func TestRpcLoginService(t *testing.T) { go StartRpcServer() ch := make(chan os.Signal, 1) signal.Notify(ch, os.Interrupt, syscall.SIGTERM) exitCode := <-ch log.Printf("Exit Code:%v", exitCode) } // TestRpcClientLogin Rpc登录客户端,连接启动的Rpc登录服务,发送请求,获取响应 func TestRpcClientLogin(t *testing.T) { targetHost := "localhost:8081" conn, err := grpc.Dial(targetHost, grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { log.Printf("Dial %s failed,err=%v ", targetHost, err) } defer conn.Close() // 构建一次用户名和密码匹配的rpc请求 c := pb.NewLoginServiceClient(conn) t1 := time.Now() rpcReply, err := c.Login(context.Background(), &pb.LoginRequest{ Username: "leebai", Password: "123456", }) log.Printf("spend time:%v", time.Now().Sub(t1).Milliseconds()) if err != nil { log.Printf("login failed,err=%v ", err) } else { log.Printf("login response: %v ", rpcReply) } 构建一次用户名和密码不匹配的rpc请求 //c2 := pb.NewLoginServiceClient(conn) //rpcReply, err = c2.Login(context.Background(), &pb.LoginRequest{ // Username: "zhangsan", // Password: "123456", //}) //if err != nil { // log.Printf("login failed,err=%v ", err) //} else { // log.Printf("login response: %v ", rpcReply) //} }
以上
func (l LoginServiceServerImpl) Login(ctx context.Context, request *pb.LoginRequest) (*pb.LoginResponse, error)
是
需要实现login_grpc.pb.go
中的接口type LoginServiceServer interface
, - 先运行
TestRpcLoginService
方法启动rpc服务程序 - 再运行
TestRpcClientLogin
方法启动rpc客户端程序,向启动的rpc服务程序发起一次rpc调用,结果如下所示:=== RUN TestRpcClientLogin 2023/05/05 14:15:08 spend time:11 2023/05/05 14:15:08 login response: code:200 msg:"success" --- PASS: TestRpcClientLogin (0.03s) PASS
- 至此就完成了一个登录请求的远程rpc服务调用
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。