前言
水了前两期博客之后终于迎来了实战环节,由于前一段一直抢不到3080,就生出了写个服务端脚本监控3080库存的想法,而在这个服务端程序中grpc的作用是把监控信息通知到我的手机上。可喜可贺的是还没有写完grpc的部分,我已经抢到了心心念念的3080了(耶)
配置Protobuf
grpc使用Protobuf作为传输数据格式,Protobuf是一种平台无关、语言无关、可扩展且轻便高效的序列化数据结构的协议,可以用于网络通信和数据存储。相比常用的JSON,proto的好处是高性能,代价是数据不可读性,以及配置起来比较麻烦。
1、首先去下载windows版本的protoc编译工具,并把bin路径配置到系统环境变量中,然后在命令行中输入 protoc 测试环境是否配置成功
https://github.com/protocolbuffers/protobuf/releases
2、安装protoc go 插件,安装成功后会在GOPATH目录下生成可执行的exe文件
go get -u github.com/golang/protobuf/protoc-gen-go
开始动手编码
1、定义protobuf文件
//proto版本
syntax="proto3";
//包名
package service;
message Empty{
}
//定义数据结构 repeated类似数组 可嵌套
message GoodsList{
repeated Goods Goods = 1;
}
message Goods {
string id = 1;
string name =2;
string state = 3;
}
//定义grpc服务接口 以及具体方法
service GetGoodsInfo{
//单向流方法,服务端可以不断向客户端传输流式数据
rpc Subscribe(Empty) returns (stream GoodsList);
}
2、编译protobuf文件,编写一个bash脚本,执行后生成go语言可访问的server.pb.go文件
protoc --go_out=plugins=grpc:. *.proto
3、编写服务端代码,首先要定义一个service结构体实现步骤1定义的接口
//GoodsService 空结构体 实现proto中的所有rpc
type GoodsService struct{}
// Subscribe 实现具体rpc 订阅商品到货信息
// Empty为方法的参数,stream是由proto中的 GetGoodsInfo+ Subscribe + Server拼成的,定义了流式结构的服务端rpc
func (*GoodsService) Subscribe(in *service.Empty, stream service.GetGoodsInfo_SubscribeServer) error {
fmt.Println("recv rpc request Subscribe , ID = ", id)
for {
select {
//有缓冲的管道,一旦有商品到货信息流入,立马通知到手机客户端
case goodsInfo := <-data.GoodsChannel:
list := service.GoodsList{}
ss := service.Goods{
Id: strconv.Itoa(goodsInfo.ID),
Name: goodsInfo.Name,
State: goodsInfo.State,
}
list.Goods = append(list.Goods, &ss)
//Send()方法发送数据到服务端,若返回错误信息则关闭此次服务
err := stream.Send(&list)
if err != nil {
fmt.Println("recv disconnect Send")
return err
}
//等待客户端channel关闭,服务端关闭此次服务
case <-stream.Context().Done():
fmt.Println("recv disconnect Recv")
return nil
}
}
}
4、开始运行grpc服务
//RunRPC 启动RPC服务
func RunRPC() error {
//监听端口
sock, err := net.Listen("tcp", ":8080")
if err != nil {
return err
}
//配置最大接受和发送数据大小
var opitions = []grpc.ServerOption{
grpc.MaxRecvMsgSize(math.MaxInt32),
grpc.MaxSendMsgSize(math.MaxInt32),
}
s := grpc.NewServer(opitions...)
myServer := &GoodsService{}
//注册gprc服务
service.RegisterGetGoodsInfoServer(s, myServer)
if err != nil {
return err
}
fmt.Println("Start GRPC Server v1.0 at Port 8080")
if err := s.Serve(sock); err != nil {
log.Fatalf("failed to serve : %v", err)
}
return nil
}
结语
至此一个可运行的grpc服务端已经编写完毕,我的思路是保持和客户端的长连接,直到客户端退出或掉线才会关闭grpc服务,其他时间则一直等待监听信息的到来。下一篇继续讲客户端gprc的编写,我们将在安卓手机上接受3080到货的消息。