RPC
是Remote Procedure Call
的简称,中文叫远程过程调用。
gRPC前面的g盲猜就是google的g, 底层是基于他们家常用的protobuf, 详情可以了解下相关内容, 此处只涉及到应用。
首先我们可以先定义proto接口文件, 内容如下:
syntax = "proto3"; // 协议版本
package proto;
option go_package = "proto/user.proto;user_proto"; //golang的包名, 涉及到golang文件生成
//request message contain the user's name password, 请求资源
message LoginRequest {
//user name
string username = 1;
//password
string password = 2;
}
// 响应资源
message LoginResponse {
//user name
string username = 1;
int64 age = 2;
//result code
uint32 code = 4;
//result msg
string msg = 5;
}
service UserService {
// rpc接口
rpc login(LoginRequest) returns (LoginResponse) {
}
}
通过上述接口定义, 可以得知, 我们定义了一个登录接口, 请求参数为请求资源里的username和password, 响应内容就是上面的响应资源。
接下来就是利用google的官方工具生成golang代码, 工具安装有两个
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
默认工具安装在GOPATH\bin下面, 可设置这个变量为环境变量
然后调用工具进行生成
protoc -I . --go-grpc_out=./ user.proto
protoc --go_out=. user.proto
上述命令可以二合一, 前面一个grpc_out的文件用于生成服务端和客户端, 后面一个用来定义数据结构
然后就可以撰写相对应的服务端和客户端了
服务端代码如下:
package main
import (
pb "RPCServerDemo/proto/proto/user.proto"
"context"
grpc2 "google.golang.org/grpc"
"log"
"net"
)
type Server struct {
pb.UnimplementedUserServiceServer
}
func (s *Server) Login(ctx context.Context, in *pb.LoginRequest) (*pb.LoginResponse, error) {
log.Printf("Received username: %s", in.Username)
log.Printf("Received password: %s", in.Password)
return &pb.LoginResponse{
Username: in.Username,
Age: 18,
Code: 0,
Msg: "login success",
}, nil
}
func main() {
lis, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatalf("failed to listen :%v", err)
}
grpc := grpc2.NewServer()
pb.RegisterUserServiceServer(grpc, &Server{})
if err := grpc.Serve(lis); err != nil {
log.Fatalf("failed to Serve: %v", err)
}
}
客户端代码如下:
package main
import (
"context"
"log"
"time"
"google.golang.org/grpc"
pb "RPCClientDemo/proto/proto/user.proto"
)
const (
address = "localhost:8080"
)
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.NewUserServiceClient(conn)
ctx, cannel := context.WithTimeout(context.Background(), time.Second*10)
defer cannel()
rsp, err := c.Login(ctx, &pb.LoginRequest{
Username: "zhangsan",
Password: "123456",
})
if err != nil {
log.Fatalf("could not login request: %v", err)
}
log.Printf("Username: %s Code: %d Msg %s", rsp.GetUsername(), rsp.Code, rsp.Msg)
}
依次启动服务端和客户端, 可以看到客户端登录后程序退出前的登录消息打印...