gRPC概述:
gRPC( Remote Procedure Call,远程过程调用)是由Google开发的一个高性能的、开源的通用的RPC框架主要用来解决性能损失的问题。
在gRPC中,我们称调用方为client,被调用方为server。 跟其他的RPC框架一样,gRPC也是基于”服务定义“的思想。 简单的来讲,就是我们通过某种方式来描述一个服务,这种描述方式是语言无关的。在这个”服务定义“的过程中,我们描述了我们提供的服务服务名是什么,有哪些方法可以被调用,这些方法有什么样的入参,有什么样的回参。在一定程度上来说类似远程的函数调用。
gRPC使客户端和服务端应用程序可以透明地进行通信,并简化了连接系统的构建。它使用HTTP/2作为通信协议,使用Protocol Buffers作为序列化协议。
环境配置:
在开始之前需要配置好proto环境 proto环境配置可以去看protobuf使用文档
首先下载下载grpc包
go get google.golang.org/grpc
如果下载失败 尝试使用代理
> set GOPROXY=https://mirrors.aliyun.com/goproxy/ //使用代理
> set GO111MODULE=on //开启go mod
> go get google.golang.org/grpc
接下来,编写proto文件 新建一个hello.proto文件
其中这里说我定义我自己的三个服务函数 建议定义一个hello服务函数先跑起来
每一个服务函数 传入一个请求消息 调用成功返回一个消息
syntax = "proto3"; //表明使用proto3语法;如果你没有指定这个,编译器会使用proto2语法
package pb; //属于哪个包
option go_package = "grpc/pb"; // 生成go文件保存到指定目录中
//option go_package = ".;message"; 这部分的内容是关于最后生成的go文件是处在哪个目录哪个包中
// .代表在当前目录生成,message代表了生成的go文件的包名是message
//定义hello请求消息
message HelloRequest {
string key = 1; //string类型
string value = 2;
string bucket=3;
map<string,string> keyValue=4;//这个对应go中的map
}
//定义hello响应消息。
message HelloReply {
string key = 1;
string value = 2;
string bucket=3;
map<string,string> keyValue=4;
string info=5;
}
//定义请求消息
message buckupRequest{
string command=1;
string flag=2;
}
//定义响应消息
message buckupReply{
string command=1;
string flag=2;
}
//定义服务,包含定义服务名、服务方法名、方法参数和返回类型
service Greets {
rpc RrpcCreateBucket (HelloRequest) returns (HelloReply) {} //创建桶
rpc RrpcDeleteBucket(HelloRequest)returns (HelloReply) {} //删除桶
rpc RrpcBuckUp(buckupRequest)returns (buckupReply){} //备份和恢复
}
// 在这我定义了一个名为RrpcCreateBucket的服务 方法的参数是HelloRequest 调用成功将返回HelloReply
然后 我们进入到proto文件的目录下 需对应自己文件名修改
我们使用protoc编译器: 把编写好的proto文件转换成go 就会得到一个 hello.pb.go的文件
protoc --go_out=plugins=grpc:. hello.proto
grpc编写:
服务端流程:
一:重写注册的函数 (声明的注册函数需全部重写)
二:新建一个服务端实例
三:监听 使用tcp
四:启动服务端
新建一个server.go 编写服务端代码:
type Server struct{ //这个结构体实现了全部方法 就是实现了接口
}
func (this *Server)RrpcCreateBucket( ctx context.Context, request *pb.HelloRequest) (*pb.HelloReply, error){
return &pb.HelloReply{
Key:request.Key ,Value:request.Value,Bucket:request.Bucket,Command:request.Command,Flag:1},nil
}
func (this *Server)RrpcDeleteBucket(ctx context.Context, request *pb.HelloRequest) (*pb.HelloReply, error){
return &pb.HelloReply{Key:request.Key,Value:request.Value,Bucket:request.Bucket,
Command:request.Command,Flag:request.Flag},nil
}
func (this *Server)RrpcBuckUp(ctx context.Context,req *pb.BuckupRequest) (*pb.BuckupReply, error){
if req.Command=="buckup"{ //如果客户端发送的请求中的command字段为buckup则进行备份
fmt.Println("备份成功")
return &pb.BuckupReply{Command:"",Flag:"0"},nil
}
fmt.Println("恢复成功")
return &pb.BuckupReply{Command:"",Flag:"0"},nil
}
func main(){
g:=grpc.NewServer() //新建一个服务端实例
pb.RegisterGreetsServer(g,&Server{}) //声明的服务函数必须实现 proto中的注册函数
lis,err:=net.Listen("tcp","127.0.0.1:10001") //TCP连接 需要监听的ip和端口号
if err!=nil{
panic(err)
}
fmt.Println("服务端开启了")
err=g.Serve(lis) //启动服务端
if err!=nil{
panic(err)
}
}
客户端流程
一:拨号连接 异常处理 延迟关闭连接
二:新建一个客户端实例
三:调用注册的函数
新建一个client.go 编写客户端代码
func ClientCreateBucket(bucket string,addr string){
conn,err:=grpc.Dial(addr,grpc.WithInsecure()) //拨号连接 对方的ip和端口号
if err!=nil{ //建立连接失败
panic("dial failed"+err.Error())
}
defer conn.Close() //延迟关闭连接
c:= pb.NewGreetsClient(conn) //新建一个客户端实例
_,err=c.RrpcCreateBucket(context.Background(),
&pb.HelloRequest{Key:"key1",Value:"value1",Bucket:bucket})
//调用 传递的pb.HelloRequest格式为hello.pb.go定义
//这里选择忽略发送回来的helloReply
if err!=nil{ //调用失败
panic("CreateBucket failed"+err.Error())
}
}
func ClientDeleteBucket(bucket ,addr string){
conn,err:=grpc.Dial(addr,grpc.WithInsecure()) //拨号连接 对方的ip和端口号
if err!=nil{
panic("dial failed"+err.Error())
}
defer conn.Close() //延迟关闭连接
c:= pb.NewGreetsClient(conn) //创建一个客户端实例
r,err:=c.RrpcDeleteBucket(context.Background(),
&pb.HelloRequest{Key:"key1",Value:"value1",Bucket:bucket})
//调用 并且传递一个HelloRequest类型的消息
//r为服务端回发的helloReply消息
if err!=nil{
panic("delete bucket failed"+err.Error())
}
fmt.Println(r.Info) //打印helloReply消息中的Info字段
}
func main(){
...//自己的业务处理
//调用client封装的函数
// 可以在这调用一个for函数循环调用客户端函数即可验证通信
}
可以把服务端函数打印输出request中的字段即可验证。