ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-07-21 18:34:08  阅读:245  来源: 互联网

标签:protoc string err proto grpc golang go


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

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

  • 准备工作
  • protoc工具的相关命令
  • proto文件的定义
  • go-grpc的实践

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有