Protobuf 命令学习

本文介绍了 Protobuf 的命令行使用,包括protobuf安装、-proto_path (-I)选项、--go_out选项、指定proto文件、执行多个proto文件及生成grpc功能。通过实例详细解析了各个选项的用法和最佳实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以下是学习笔记目录:

protobuf 简介

微服务很流行,go语言也很流行,这两者加起来的grpc服务也很流行。其中 grpc 使用的是ProtoBuf 作为内容传输中间件,看下它的说明:

protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。

Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法

它对比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。

看样子确实很厉害!

0. protobuf 安装

protobuf 的安装很简单,如果是Mac的话,一条命令就搞定了:

brew install protobuf

如果是其他系统,请参考官方文档,也很简单。

安装好的服务,命令执行的关键字是 protoc xx xx xx

首先,这是我的例子的目录结构:

/Users/smallyang/www/gowww/go-grpc-example

├── client
├── go.mod
├── go.sum
├── main.go
├── proto
│   ├── hello.proto
│   └── server.proto
└── server.go

其中proto是我用来存放*.proto文件的文件夹目录名。

1. -proto_path (-I)选项

protoc --proto_path=proto --go_out=.  proto/hello.proto

--proto_path 可以简写为-I ,表示读取*.proto文件的目录, 可以是绝对路径,也可是是相对路径,如果这个选项不指定,那么就会读取protoc命令执行时候的当前的目录。注意=左右都不能有空格

比如:

protoc -I=/Users/smallyang/www/gowww/go-grpc-example/proto --go_out=.  hello.proto

这个极端的例子,指定的读取的proto目录的路径为:/Users/smallyang/www/gowww/go-grpc-example/proto

当然,一般我们不会这么变态和繁琐,我们一般是先进入项目的目录中去执行protoc生成

cd /Users/smallyang/www/gowww/go-grpc-example/
protoc -I=proto --go_out=.  hello.proto

或者,我们更进一步,去掉这个-I选项,我们直接再进入proto文件夹中,去执行里面的文件:

cd /Users/smallyang/www/gowww/go-grpc-example/
cd proto
protoc --go_out=.  hello.proto

那么这样就读取的是/proto这个文件夹下得proto文件。

所以,最佳实践就是去掉这个-I选项,直接进入proto的文件夹

protoc --go_out=.  hello.proto

2. --go_out 选项

--go_out 表示将*.ptoto文件转换为golang语言,是一个特定的选项,它包含2部分,前半部分是用转换成哪个语言,go表示转换为go语言,如果是其他语言,也可以是:

--php_out 
--csharp_out
--java_out
--js_out
....

但是,很奇葩的是,protobuf 的源码服务里面,唯独没有对go语言的支持,黑人问号???

点进去看,源码里主流语言都有,就是没有golang (是1个单独的项目) :

https://github.com/protocolbuffers/protobuf/tree/2db0e9812a8774f5266370b7a6eae4e4e5a2cdd0#protobuf-runtime-installation

比如你要使用--go_out ,那么就要下载和按照对应的生成go的服务文件。

所幸的是,下载和使用很简单,执行下面这个命令就可以了:

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

它会在$GOPATH/bin 目录下生成1个可执行的protoc-gen-go文件。所以,这个文件不要删了。不然你使用--go_out 时,会找不到protoc-gen-go,提示报错。

PS 我测试了一下,生成其他语言文件,是可以直接使用的,就go语言需要单独下载和安装生成服务

➜  proto git:(master) ✗ protoc --php_out=:. hello.proto  
➜  proto git:(master) ✗ protoc --js_out=:. hello.proto
➜  proto git:(master) ✗ protoc --ruby_out=:. hello.proto
➜  proto git:(master) ✗ protoc --python_out=:. hello.proto
➜  proto git:(master) ✗ protoc --csharp_out=:. hello.proto

如果源码里有这个语言,但是执行的时候,报错,可能是需要手动安装服务,具体,可以查看对应的语言文档。

我们继续用--go_out 来举例说明:

--go_out=path

= 后半部分,表示的是转换生成后的pb.go文件,放在哪个文件夹下。注意=左右都不能有空格

同样,他可以是绝对路径,也可以相对路径。比如:

 protoc --go_out=/Users/smallyang/www/gowww/go-grpc-example/proto  hello.proto 

或者相对路径:

protoc --go_out=../client hello.proto

当然,我们一般也不会这么恶心和繁琐,一般是结合-I选项来弄,-I我们一般会省略掉,直接是进入proto文件夹目录执行,那么--go_out也是直接生成在当前proto文件夹中:

protoc --go_out=:. hello.proto

或者

protoc --go_out=. hello.proto

至于=:.=. 有啥区别呢? 因为--go_out 他既可以指定生成目录,又能指定使用啥插件,这个在接下来生成grpc的时候,我再讲。但是他们都表示的是将生成的pb.go文件放入当前的目录下。

所以,最佳实践就是直接将pb.go文件生成在当前proto文件夹中:

--go_out=:.

3. 指定哪个proto源头文件

前面的例子,我们用的hello.proto文件作为执行源头文件

看个例子:

protoc --go_out=:. ./hello.proto
protoc --go_out=:. hello.proto

上面2个是等价的,都是读取当前目录下得hello.proto文件

来个变态的:

protoc --go_out=:. ./b/c/hello.proto
protoc --go_out=:. b/c/hello.proto 

他们表示读取的是:proto/b/c/hello.proto文件

再结合-I,来个更变态的:

 protoc -I=proto --go_out=:. b/c/hello.proto

这个目录就是2部分结合起来了:proto + b/c/hello.proto = /proto/b/c/hello.proto

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

这个目录就是2部分结合起来了:proto + hello.proto = /proto/hello.proto

但是,下面这个,就真的看不懂了:

 protoc -I=proto --go_out=:. proto/hello.proto

我已经指定了-I目录,为啥我这样写:proto/hello.proto 还是成功的。结合上面,不应该目录变成:proto/proto/hello.proto吗?应该报个错,说找不到文件啊。

难道这样写,读取的是绝对路径???

那我就写死绝对路径看看:

 protoc -I=proto --go_out=:. /Users/smallyang/www/gowww/go-grpc-example/proto/hello.proto

结果报错了:

/Users/smallyang/www/gowww/go-grpc-example/proto/hello.proto: File does not reside within any path specified using --proto_path (or -I).  You must specify a --proto_path which encompasses this file.  Note that the proto_path must be an exact prefix of the .proto file names -- protoc is too dumb to figure out when two paths (e.g. absolute and relative) are equivalent (it's harder than you think).

意思的是在 --proto_path 里找不到这个绝对路径的地址。所以,这个地方,不支持绝对路径,只能是配合 --proto_path指定来查找。

所以,回到上面这个例子:

 protoc -I=proto --go_out=:. proto/hello.proto

我既指定了 --proto_path 为:proto文件夹,又去读取包含这个目录的读取方式:proto/hello.proto,结果没报错。所以,它应该是对比了一下,这2个目录结构是否相等 (two paths (e.g. absolute and relative) are equivalent )

如果相等,就直接读取了,不拼接路径:

protoc -I=proto --go_out=:. proto/hello.proto

# /proto/hello.proto

如果不相等,就去拼接这2个选项的路径来读取:

protoc -I=proto --go_out=:. b/c/hello.proto

# /proto/b/chello.proto

所以,如果不指定-I参数,那么就不会拼接和做相等匹配,直接读取这个路径的文件。如果不存在就报错。

所以最佳实践是去掉-I 参数,直接读取当前目录下得proto文件

protoc --go_out=:. hello.proto

4. 执行多个proto文件

是可以同时执行多个proto文件的。多个文件用空格分开

protoc --go_out=:. hello.proto server.proto

这样就会在当前目录生成2个pb文件。但是会去校验变量去重,这个以后再讲。

也可以用统配符号 * 来匹配多个文件:

protoc --go_out=:. *.proto

5. 指定grpc选项,生成grpc功能

我们一般如果是go语言的话,用proto 都是结合grpc来用的。要结合--go_out来使用:

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

要想使用grpc功能,那么proto文件里得定义rpc相关的服务,这样生成的pb.go文件,才会生成相关rpc数据:

vi hello.proto

package proto;

option go_package = ".;proto";

message Yang {
    string name=1;
    int32 age=2;
}

message Id {
    int32 uid=1;
}

# 要生成server rpc代码
service ServiceSearch{
    rpc SaveUser(Yang) returns (Id){}
    rpc UserInfo(Id) returns (Yang){}
}

再来看:. 的问题。上面没有生成gprc 插件,所以:. = . ,那现在我们需要使用grpc插件,那么 这个 : 就是一个分隔符了,分隔成2部分:

--go_out === plugins的类型 : 输出的路径

 protoc --go_out=plugins=grpc:./b/c hello.proto

他表示的是:用grpc服务生成的pb.go 文件,放入当前目录的 /b/c 目录下,如下图所示:

.
├── b
│	└── c
│		└── hello.pb.go
├── hello.proto
└── server.proto

执行命令的时候,会去检查你是否已经下载了 grpc 的库,google.golang.org/grpc,没有的话,会去自动下载。

所以一般情况下,我们也不会搞这么复杂,所以最佳实践是生成的grpc服务的pb.gp文件也生成在当前的proto文件夹目录下

这样子写:

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

不需要grpc:

protoc --go_out=. hello.proto 

常用的执行命令就的学习完毕了,下一篇讲 proto文件的语法和规则

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值