protobuf配置和使用
-
下载对应zip包, 解压
https://github.com/protocolbuffers/protobuf/releases -
配置环境变量:
在用户系统变量Path最后添加刚刚解压的bin目录,例如: G:\soft\protobuf\bin
mac 版本看这里 链接 -
验证是否配置正确:
打开终端,输入protoc,如果输出下面内容,代码配置成功。
-
安装protoc-gen-go库
在此之前要设置go的环境变量:- GO111MODULE=on
- GOPROXY=https://goproxy.cn,direct
然后:
go get github.com/golang/protobuf/protoc-gen-go
-
定义test.proto文件, 输入下面数据 :
syntax = "proto3"; //proto版本信息
package test; //定义属于哪个包
//如果报waring就加上这个,不加也能成功
// ./aaa - 表示生成的go文件的存放地址,会自动生成目录的
// test - 表示生成的go文件所属的包名
option go_package = "./aaa;test";
//message是固定格式,表示消息, Order是数据对象的名
// required - 必填项, optional - 选填项, 这两个是proto2的参数,在proto3取消了
// = 1, = 2, = 3是字段的顺序, 为了保证数据顺序的统一
message Order{
int32 order_id = 1;
int64 num = 2;
string name = 3;
}
-
进入test.proto所在路径, 编译proto文件
- .指的是编译后的文件路径, 这里使用当前路径就行,具体路径在proto文件里面定义了
- test.proto指要编译的文件
注意 = 后面不能有空格
protoc --go_out =. test.proto
-
注意,如果要编译grpc可用的proto,需要使用如下命令
protoc --go_out=plugins=grpc:. test.proto -
再注意,新版本如果用上面的命令报如下错:
--go_out: protoc-gen-go: plugins are not supported; use 'protoc --go-grpc_out=...' to generate gRPC See https://grpc.io/docs/languages/go/quickstart/#regenerate-grpc-code for more information.
则先安装 go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
然后进入proto文件的当前路径, 执行:
protoc -I . --go_out=. --go-grpc_out=. ./test.proto
ps : 这里有个坑,如果你发现无法编译,报这个错的话,protoc-gen-go-grpc: program not found or is not executable as xxxxxxxxxx
需要安装下面grpc gen插件:
go get -u google.golang.org/protobuf/cmd/protoc-gen-go
go install google.golang.org/protobuf/cmd/protoc-gen-go
go get -u google.golang.org/grpc/cmd/protoc-gen-go-grpc
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
- 使用上面生成的 test.pb.go文件进行数据封包和拆包
func main(){
fmt.Println("hey_wei_gou")
//创建消息对象
msg_test := &test.Order{
OrderId: *proto.Int32(12),
Num: *proto.Int64(22),
Name: *proto.String("fuck"),
}
//序列化
msgDataEncoding,err := proto.Marshal(msg_test)
if err!=nil{
fmt.Println("err:",err.Error())
panic(err)
return
}
//反序列化
msgEmpty := test.Order{}
err = proto.Unmarshal(msgDataEncoding,&msgEmpty)
if err!=nil{
fmt.Println("err:",err.Error())
panic(err)
return
}
fmt.Println("order_id:",msgEmpty.GetOrderId())
fmt.Println("num:",msgEmpty.GetNum())
fmt.Println("name:",msgEmpty.GetName())
}
go内置rpc的使用
一图胜千言
上代码:
-
message.proto :
syntax = "proto3"; package message; option go_package = ".;message"; //订单请求参数 message OrderRequest{ string orderId = 1; int64 timeStamp = 2; } //订单信息 message OrderInfo{ string OrderId = 1; string OrderName = 2; string OrderStatus = 3; }
-
server.go
package main
import (
"errors"
"net"
"net/http"
"net/rpc"
"testRPC/rpcAndProto/message"
"time"
)
type OrderService struct {
}
func (os *OrderService) GetOrderInfo(request message.OrderRequest, response *message.OrderInfo)error{
//创建订单信息
orderMap := map[string]message.OrderInfo{
"1":{OrderId: "1",OrderName: "衣服",OrderStatus: "已付款"},
"2":{OrderId: "2",OrderName: "手机",OrderStatus: "未付款"},
"3":{OrderId: "3",OrderName: "电脑",OrderStatus: "已付款"},
}
//得到当前时间
current := time.Now().Unix()
if (request.TimeStamp>current){
//返回异常
*response = message.OrderInfo{OrderId: "0",OrderName: "",OrderStatus: "订单信息异常"}
}else {
result := orderMap[request.OrderId]
if (result.OrderId!=""){
//找到对应的d订单id,返回正常数据
*response = orderMap[request.OrderId]
}else {
return errors.New("server error")
}
}
return nil
}
func main(){
//1.初始化结构指针
orderServer := new(OrderService)
//2.调用net/rpc包里面的功能进行服务对象注册
err := rpc.RegisterName("routeName",orderServer)
if err!=nil{
panic(err.Error())
}
//3.下面的函数可以把 machUtil里面包含的功能函数注册到HTTP协议中,调用者可以使用http方式进行数据传输
rpc.HandleHTTP()
//4.监听
listen,err := net.Listen("tcp",":8081")
if err!=nil{
panic(err.Error())
}
//5.处理请求
http.Serve(listen,nil)
}
- client.go
package main
import (
"fmt"
"net/rpc"
"testRPC/rpcAndProto/message"
"time"
)
func main(){
//1.链接服务器
client,err := rpc.DialHTTP("tcp","localhost:8081")
if err!=nil{
panic(err.Error())
}
//2.封装请求
timeStamp := time.Now().Unix()
requset := message.OrderRequest{OrderId: "2",TimeStamp: timeStamp}
var response *message.OrderInfo //声明接受参数
//3.同步调用
err = client.Call("routeName.GetOrderInfo",requset,&response)
if err!=nil{
panic(err.Error())
}
fmt.Println("resp.OrderId:",response.OrderId)
fmt.Println("resp.OrderName:",response.OrderName)
fmt.Println("resp.OrderStatus:",response.OrderStatus)
}
编译proto,运行server.go 再运行 client.go, 齐活…
grpc使用
- 首先要安装grpc,怎么安装这里不赘述了,直接上代码, 文件结构和上面内置rpc的结构一样
- message.proto:
syntax = "proto3";
package message;
option go_package = ".;message";
//订单请求参数
message OrderRequest{
string orderId = 1;
int64 timeStamp = 2;
}
//订单信息
message OrderInfo{
string OrderId = 1;
string OrderName = 2;
string OrderStatus = 3;
}
//声明服务的方法(函数), GetOrderInfo-函数, OrderRequest-请求参数,OrderInfo-返回参数
//OrderService是服务名,在对应的pb.go里面,会有注册这个服务的对应函数, RegisterOrderServiceServer
service OrderService{
rpc GetOrderInfo(OrderRequest) returns (OrderInfo);
}
- server.go
package main
import (
"context"
"errors"
"fmt"
"net"
"net/rpc"
"test_grpc/message"
"time"
"google.golang.org/grpc"
)
type OrderServiceImpl struct {
}
func (os *OrderServiceImpl) GetOrderInfo(ctx context.Context,
request *message.OrderRequest)(*message.OrderInfo,error){
//创建订单信息
orderMap := map[string]message.OrderInfo{
"1":{OrderId: "1",OrderName: "衣服",OrderStatus: "已付款"},
"2":{OrderId: "2",OrderName: "手机",OrderStatus: "未付款"},
"3":{OrderId: "3",OrderName: "电脑",OrderStatus: "已付款"},
}
//得到当前时间
current := time.Now().Unix()
if (request.TimeStamp>current){
//返回异常
return &message.OrderInfo{OrderId: "0",OrderName: "",OrderStatus: "订单信息异常"},errors.New("timeout")
}else {
result := orderMap[request.OrderId]
if (result.OrderId!=""){
//找到对应的d订单id,返回正常数据
fmt.Println("result:",result)
return &result,nil
}else {
return nil, errors.New("server error")
}
}
return nil,nil
}
func main(){
//1.初始化grpc
server := grpc.NewServer()
message.RegisterOrderServiceServer(server,new(OrderServiceImpl))
//3.下面的函数可以把 machUtil里面包含的功能函数注册到HTTP协议中,调用者可以使用http方式进行数据传输
rpc.HandleHTTP()
//4.监听
listen,err := net.Listen("tcp",":8090")
if err!=nil{
panic(err.Error())
}
//5.处理请求
_ = server.Serve(listen)
}
- client.go
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"test_grpc/message"
"time"
)
func main(){
//1.链接服务器
conn,err := grpc.Dial("localhost:8090",grpc.WithInsecure())
if err!=nil{
panic(err.Error())
}
defer conn.Close()
//创建连接
orderServiceClient := message.NewOrderServiceClient(conn)
//构造请求参数
orderRequest := &message.OrderRequest{
OrderId: "3",
TimeStamp: time.Now().Unix(),
}
//发送请求并且得到回参
orderInfo,err := orderServiceClient.GetOrderInfo(context.Background(),orderRequest)
if err!=nil{
panic(err.Error())
}
if orderInfo!=nil{
fmt.Println("orderID:",orderInfo.OrderId)
fmt.Println("orderName:",orderInfo.OrderName)
fmt.Println("orderName:",orderInfo.OrderStatus)
}
}
编译proto,运行server.go 再运行 client.go, 齐活…
注意,注意,编译grpc可用的proto命令如下:
protoc --go_out=plugins=grpc:. xxx.proto
上面报错则执行新命令(具体看上面的例子):
protoc -I . --go_out=. --go-grpc_out=. ./xxx.proto