gRPC 是一个高性能、开源和通用的 RPC 框架,基于HTTP2.0实现,具体原理及其他不再多说,百度/google有很多文章,这里主要分享一下如何搭建grpc环境以及如何用插件自动生成*.pb.go代码(以下分享均基于CentOs7)
下文中如果echo $GOPATH为空,则请用绝对路径代替GOPATH
yum install -y golang(安装成功后输入go version可以看到对应版本号)
mkdir -p $GOPATH/src/learn/vendor/github.com/golang
mkdir -p $GOPATH/src/learn/vendor/golang.org/x
mkdir -p $GOPATH/src/learn/vendor/google.golang.org
由于git上这些仓库都被墙了,拉的很慢或者经常失败,在gitee上将相关仓库同步了一份,方便开发学习
git仓库地址 | gitee仓库地址 | 存放文件夹地址 |
---|---|---|
https://github.com/grpc/grpc-go.git | https://gitee.com/it-monkey/grpc-go.git | vendor/google.golang.org/grpc(需要将grpc-go重命名为grpc) |
https://github.com/google/go-genproto.git | https://gitee.com/it-monkey/go-genproto.git | vendor/google.golang.org/genproto(需要将go-genproto重命名为genproto) |
https://github.com/golang/protobuf | https://gitee.com/it-monkey/protobuf.git | vendor/github.com/golang/protobuf |
https://github.com/protocolbuffers/protobuf-go.git | https://gitee.com/it-monkey/protobuf-go.git | vendor/google.golang.org/protobuf(需要将protobuf-go重命名为protobuf) |
https://github.com/golang/net.git | https://gitee.com/it-monkey/net.git | github.com/golang/net |
https://github.com/golang/sys.git | https://gitee.com/it-monkey/sys.git | github.com/golang/sys |
https://github.com/golang/text.git | https://gitee.com/it-monkey/text.git | github.com/golang/text |
下面是我的目录树结构
|-- github.com
| `-- golang
| `-- protobuf //grpc的依赖库
|-- golang.org
| `-- x //grpc的依赖库
| |-- net
| |-- sys
| `-- text
`-- google.golang.org
|-- genproto //protoc-gen-go-grpc的源码
|-- grpc //grpc源码
`-- protobuf //protoc-gen-go的源码
其实刚才拉的仓库里已经有了广泛的demo,就在vendor/google.golang.org/grpc/examples/helloworld,将vendor/google.golang.org/grpc/examples/helloworld拷贝出来测试
拷贝helloworld Demo : cp -r $GOPATH/src/learn/vendor/google.golang.org/grpc/examples/helloworld $GOPATH/src/learn/
进入server端编译&运行: cd $GOPATH/src/learn/helloworld/greeter_server
go build main.go
./main
再开一个窗口编译运行client: cd $GOPATH/src/learn/helloworld/greeter_client
go build main.go
./main
下面是介绍编译proto文件&自动生成*.pb.go的工具protoc + protoc-gen-go-grpc (老版本用的是protoc-gen-go,我试过,最新的grpc只用老版本生成的.pb.go少很多东西,无法使用,网上查了一下,说是现在官方在工具这一块变动较大)
https://github.com/protocolbuffers/protobuf/releases/download/v3.14.0/protoc-3.14.0-linux-x86_64.zip
下载之后解压,将其中的bin目录下的protoc文件放到$GOPATH/bin目录下
再给与可执行权限chmod a+x protoc
将$GOPATH/bin加入PATH: export PATH=$PATH:$GOPATH/bin
go install $GOPATH/src/learn/vendor/google.golang.org/protobuf/cmd/protoc-gen-go
其实上面我们已经将protoc-gen-go-grpc的源码下载下来了(vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc),现在只需要编译安装到$GOPATH/bin下即可
运行如下命令即可安装
go install $GOPATH/src/learn/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc
要确保$GOPATH/bin下有如下3个文件
接下来简单写一个proto文件
syntax = "proto3";
package calc;
message CalcRequest{
int32 a = 1;
int32 b = 2;
}
message CalcReply{
int32 ans = 1;
}
service Calc{
rpc Add(CalcRequest) returns (CalcReply){}
}
很简单,里面只有一个Add方法,内容就不多介绍了,下面用protoc-gen-go-grpc生成一下试试
能生成calc_grpc.pb.go以及calc.pb.go即为成功
下面再顺带把自己写的测试的server以及client贴出来(参照官方的helloworld写的)
先贴一下的的工程目录
|-- calc
| |--- calc_grpc.pb.go
| |--- calc.pb.go
| `--- calc.proto
|-- calcClient
| `--- main.go
`-- calcServer
`--- main.go
server端代码
package main
import (
"learn/gRpcTest/calc"
"context"
"google.golang.org/grpc"
"log"
"net"
)
const (
port = ":10024"
)
type server struct{
calc.UnimplementedCalcServer
}
func main(){
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
calc.RegisterCalcServer(s, &server{})
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
func (s *server)Add(ctx context.Context, in *calc.CalcRequest)(*calc.CalcReply, error){
log.Printf("server Add called, param1:%d, param2:%d", in.A, in.B)
return &calc.CalcReply{
Ans: in.A + in.B,
}, nil
}
func (s *server)mustEmbedUnimplementedCalcServer() {}
client端代码
package main
import (
"learn/gRpcTest/calc"
"context"
"google.golang.org/grpc"
"log"
"time"
)
const(
address = "localhost:10024"
)
func main(){
conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
client := calc.NewCalcClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
ans, err := client.Add(ctx, &calc.CalcRequest{
A: 10,
B: 20,
})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("10+20 = %d", ans.GetAns())
}
大家可以运行一下试试