其他分享
首页 > 其他分享> > [go-每日一库] golang-grpc库-protoc基本参数与简单实践(一)

[go-每日一库] golang-grpc库-protoc基本参数与简单实践(一)

作者:互联网

grpc使用protobuf进行序列化、反序列化,通常用protoc作为编译工具,对于go使用grpc作为rpc的框架,由于protoc工具未实现go-generate,我们需要使用protoc-gen-go插件帮我们生成go文件。

本文的分享分为以下方面:

1.准备工作

用go实现grpc的编码,首先下载protoc和protoc-gen-go工具插件。

protoc
官方下载地址:https://github.com/google/protobuf/releases

根据自己的操作系统选择对应版本下载后解压,另外记得设置环境变量:

如果是win平台,直接解压,然后编辑环境变量,add一下即可。

如果是linux平台,编辑/etc/profile,加入解压后的protoc的文件夹,最后source后就可以了。

安装后验证:

protoc --version
libprotoc 3.19.4

protoc-gen-go
命令行下载:

$ go get google.golang.org/protobuf/cmd/protoc-gen-go@latest
$ go get google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

2.protoc命令参数

受限篇幅,命令参数仅针对常用参数,-I[--proto_path]xx_out

-I/--proto_path
指定导入的proto文件的路径,如-I,我们可以用-I.,指定本文件夹下的proto文件,如果是proto_path,如--proto_path=$PATH即可。

XX_out
该参数指定protoc工具生成对应编程语言的service文件,如go_out,在使用时--go_out=plugins=grpc:.,即指明grpc的插件,本文件夹下。

3.proto文件的定义

首先看个usage:

syntax = "proto3"; // version

package demo; // pkg name

option go_package = "./"; // 注意包名, client、server should import pkg

// define request body
message helloRequest {
  string name = 1; // arg-1, type: string, field: name
  int64 id = 2; // arg-2, type: int64, field: id
}

// define response body
message helloResponse {
  string resp = 1; // arg-1, type: string, field: resp
}

// define service
service helloService {
  rpc hello(helloRequest) returns (helloResponse) {} // rpc service, func: hello, params: helloRequest, return helloResponse
}

syntax
指明protoc的版本

package
指明pkg名,用以取分不同的serivce文件,也指定当前的proto文件属于那个包

options
指定编译后的文件的输出目录

message
定义参数

service
定义服务名

接着看看在定义参数的一些注意事项:
支持的数据类型

复杂数据类型
定义List列表(值可以是普通变量,也可以复杂对象):

message ComplexObject {
   repeated string sons = 4; // List列表
   repeated Result result = 6; // 复杂的对象List
}

// 定义一个新的对象
message Result {
  string url = 1;
  string title = 2;
  repeated string snippets = 3;
}

定义枚举成员:

message ComplexObject {
    ...
    Gender gender = 5; // Enum值
    ...
}
enum Gender {
  MAN = 0;
  WOMAN = 1;
}

定义Any对象(用于定义任意的值):

message ComplexObject {
   repeated google.protobuf.Any any = 7; // Any对象
}

定义Map对象(key,value都可以是复杂对象):

message ComplexObject {
   map<string, MapVaule> map = 8; // 定义Map对象
}
// 定义Map的value值
message MapVaule {
  string mapValue = 1;
}

通过 reserved保留 Assigning Tags和filed name用于将来扩展用:

message ComplexObject {

    reserved 12, 15, 9 to 11; // 预留将来使用的Assigning Tags,
    reserved "foo", "bar"; // 预留将来使用的filed name
}

4.protoc的实践

c/s目录结构

proto文件

syntax = "proto3"; // version

package demo; // pkg name

option go_package = "./"; // 注意包名, client、server should import pkg

// define request body
message helloRequest {
  string name = 1; // arg-1, type: string, field: name
  int64 id = 2; // arg-2, type: int64, field: id
}

// define response body
message helloResponse {
  string resp = 1; // arg-1, type: string, field: resp
}

// define service
service helloService {
  rpc hello(helloRequest) returns (helloResponse) {} // rpc service, func: hello, params: helloRequest, return helloResponse
}

生成service文件
进入proto目录:

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

go.mod

module demo

go 1.16

replace (
	../go-grpc-v1 => ../demo
)

require (
	google.golang.org/grpc v1.48.0
	google.golang.org/protobuf v1.28.0
)

server

package main

import (
	"context"
	hellopb "demo/proto"
	"fmt"
	"google.golang.org/grpc"
	"log"
	"net"
)

const (
	ADDR string = "localhost:50052"
)

func main()  {
	log.Println("grpc server is up...")
	lis, err := net.Listen("tcp", ADDR)
	if err != nil {
		log.Fatal(err.Error())
	}

	s := grpc.NewServer()
	hellopb.RegisterHelloServiceServer(s, &Service{})
	err = s.Serve(lis)
	if err != nil {
		log.Fatal(err.Error())
	}
}

type Service struct {}

func (s *Service) Hello(ctx context.Context, req *hellopb.HelloRequest) (*hellopb.HelloResponse, error) {
	fmt.Printf("receive request, params -> name: %s, id: %d\n", req.Name, req.Id)
	return &hellopb.HelloResponse{
		Resp: fmt.Sprintf("resp from server, name: %s, id: %d", req.GetName(), req.GetId()),
	}, nil
}

client

package main

import (
	"context"
	hellopb "demo/proto"
	"fmt"
	"google.golang.org/grpc"
	"log"
)

func main()  {
	conn, err := grpc.Dial("localhost:50052", grpc.WithInsecure()) // conn rpc server
	if err != nil {
		log.Fatal(err.Error())
	}
	defer conn.Close()

	client := hellopb.NewHelloServiceClient(conn) // new a client
	resp, err := client.Hello(context.Background(), &hellopb.HelloRequest{Name: "Bob", Id: 1000}) // send request, receive response
	if err != nil {
		log.Fatal(err.Error())
	}
	fmt.Println(resp.Resp)
}

最后先跑server,再跑client,即完成c/s的grpc的简单实践。

参考:

标签:protoc,string,err,proto,grpc,golang,go
来源: https://www.cnblogs.com/davis12/p/16503010.html