protobuf使用

安装 #

protoc安装 #

安装地址:https://github.com/protocolbuffers/protobuf

右侧有个Releases,点击进入可以看到各操作系统的版本,现在相应版本protoc,我这是windows amd64

保存到GOPATH下的/bin目录下

查看版本

protoc --version

安装go版本插件 #

go get -u github.com/golang/protobuf/proto
go get -u github.com/golang/protobuf/protoc-gen-go

protobuf格式 #

在protobuf中,协议是由一系列的消息(message)组成的,如下所示:

syntax = "proto3";
package Service;
//可以通过import导入其它proto
//import "taskModels.proto";
option go_package = "./;protos"; //两个参数一个是生成地址,一个是包名

enum Gender {
		MAN = 0;
		FEMAN = 1;
}

message Student {
	 string name = 1;  //1表示标识符,同一个message中不能重复
	 int32 coutry = 2;
	Gender gender = 3;
}

message Teacher {
	 string name = 1;
	 string class = 2;
	 string object = 3;
	 Gender gender = 4;
}

message School {
	repeated Student studentList = 1;
	repeated Teacher techerList = 2;
}

repeated:表示该字段可以包含多个元素,列表数组

编译生成pb.go文件 #

protoc -I ./protos --go_out=./ protos/user.proto

-I –proto_path 指定对导入文件的搜索路径,若不指定,则为当前路径

–go_out=../ 指定生成pb文件的目标目录

protos/user.proto 消息结构文件

在Service目录下执行编译命令

结构

主函数

package main

import (
	"fmt"
	protos "micro_test/Service"
)

func main()  {
	std := &protos.Student{
		Name:   "laozhu",
		Coutry: 0,
		Gender: 0,
	}
	teacher := &protos.Teacher{
		Name:   "cjh",
		Class:  "1班",
		Object: "语文",
		Gender: 0,
	}

	schools := &protos.School{
		StudentList: []*protos.Student{std},
		TecherList:   []*protos.Teacher{teacher},
	}

	fmt.Println(schools)
}

输出

studentList:{name:"laozhu"}  techerList:{name:"cjh"  class:"1班"  object:"语文"}

RPC调用proto #

安装gRPC #

 go get -u google.golang.org/grpc

创建proto文件 #

hello.proto

//默认是Proto2
syntax = "proto3";

// 指定包名
//package pb;
option go_package = "./;protos";   //两个参数一个是生成地址,一个是包名

// 定义消息体
message Response {
    int32           error     = 1;   //1表示标识符,同一个message中不能重复
    string          ans       = 2;
}

// 消息体嵌套
message Request {
    string          name = 1;
}


//声明rpc调用方法
service ii14 {
    rpc sayHello(Request) returns (Response);
}

编译 #

使用了grpc插件 –go_out=plugins=grpc:.

protoc -I ./protos --go_out=plugins=grpc:./ protos/hello.proto

grpc测试 #

将上述protoc编译出来的go文件放到下述文件中同目录下引用使用

服务端代码 #

server/server.go

package main

import (
	context "context"
	"fmt"
	protos "micro_test/Service"
	"net"
	"google.golang.org/grpc"
)

//定义服务
type RPCService struct {
}

//实现服务方法
func (srv *RPCService) SayHello(ctx context.Context, req *protos.Request) (*protos.Response, error) {

	name := req.Name

	return &protos.Response{Error: 0, Ans: "Hello " + name}, nil
}

func main() {
	
    //启动grpc服务
	grpcSrv := grpc.NewServer()

    //实现服务接口
	protos.RegisterIi14Server(grpcSrv, new(RPCService))

	listener, err := net.Listen("tcp", "127.0.0.1:8080")
	if err != nil {
		fmt.Println("net Listen error", err)
	}

    //启动侦听服务
	grpcSrv.Serve(listener)
}

客户端代码 #

client/server.go

package main

import (
	context "context"
	"fmt"
	grpc "google.golang.org/grpc"
	protos "micro_test/Service"
)

func main() {
    //连接grpc地址
	conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure())
	if err != nil {
		fmt.Println("grpc Dial error", err)
		return
	}

    //调用call client
	client := protos.NewIi14Client(conn)
	
    //执行客户端的函数SayHello
	rep, err := client.SayHello(context.TODO(), &protos.Request{Name: "zy"})
	if err == nil {
		fmt.Println("execute succ ", rep)
	}
}

Micro调用 #

安装micro命令 #

go get github.com/micro/protoc-gen-micro
go get github.com/micro/go-micro/v2

创建proto文件 #

用户模型userModels.proto

syntax="proto3";
package services;
option go_package="../;protos";

message UserModel{
    // @inject_tag: json:"id"
    uint32 ID=1;
    // @inject_tag: json:"user_name"
    string UserName=2;
    // @inject_tag: json:"created_at"
    int64 CreatedAt=3;
    // @inject_tag: json:"updated_at"
    int64 UpdatedAt=4;
    // @inject_tag: json:"deleted_at"
    int64 DeletedAt=5;
}

用户业务userService.proto

syntax = "proto3";
option go_package="../;protos";

service Greeter {
	rpc Hello(Request) returns (Response) {}
}

message Request {
	string name = 1;
}

message Response {
	string msg = 1;
}

编译 #

在protos目录下执行

protoc  --micro_out=. --go_out=. greeter.proto

调用调试 #

服务端 #

package main

import (
	protos "micro_test/Service"
	"github.com/micro/go-micro/v2"
	"context"
)

type Greeter struct {

}

func (g *Greeter) Hello(ctx context.Context, req *protos.Greeter.Request, rsp *protos.Response) error {
	rsp.Msg = "Hello " + req.Name
	return nil
}


func main()  {
	microService := micro.NewService(
		micro.Name("rpcGreeterService"), // 微服务名字
		micro.Address("127.0.0.1:8082"),
	)
	microService.Init()

	_ = protos.RegisterGreeterHandler(microService.Server(), &Greeter{})

	_ = microService.Run()
}

客户端代码 #

	microService := micro.NewService(
		micro.Name("greeterService.client"),
	)
	// 用户服务调用实例
	greeterService := protos.NewGreeterService("rpcGreeterService",microService.Client())
	
		server := web.NewService(
		web.Name("httpService"),
		web.Address("127.0.0.1:4000"),
		//将服务调用实例使用gin处理
		web.Handler(router(greeterService)),
		web.RegisterTTL(time.Second*30),
		web.RegisterInterval(time.Second*15),
		web.Metadata(map[string]string{"protocol": "http"}),
	)
	//接收命令行参数
	_ = server.Init()
	_ = server.Run()
	

//定义路由
func router(service interface{}) *gin.Engine {
	ginRouter := gin.Default()
	ginRoouer.GET("greeter",function(ctx *gin.Context) {
		var req *&protos.Request
		cxt.Bind(&req)
		greeterService := service.(protos.GreeterService)
		resp,err := greeterService.SayHello(context.Background(),&req)
		ginCtx.JSON(http.StatusOK, gin.H{"data": resp})
	}
}