当前位置: 首页 > 工具软件 > grpc-go > 使用案例 >

go grpc的使用

程阳平
2023-12-01

基础篇

基础篇主要是让大家熟悉protoc的一些基本参数,以及常见用法,项目结构如下:

├── proto1
│   ├── greeter
│   │   ├── greeter.proto
│   │   └── greeter_v2.proto
│   └── pb_go

greeter.proto文件内容:

syntax = "proto3";

package greeter;

option go_package="proto1/greeter";

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

编译命令如下:

protoc -I . --go_out=. proto1/greeter/greeter.proto

上面的指令可以拆解为三部分,分别对应protoc的三个重要参数,我们首先来看看protoc提供了哪些参数:

$ protoc --help
Usage: protoc [OPTION] PROTO_FILES

  -IPATH, --proto_path=PATH   指定搜索路径
  --plugin=EXECUTABLE:
  
  ....
 
  --cpp_out=OUT_DIR           Generate C++ header and source.
  --csharp_out=OUT_DIR        Generate C# source file.
  --java_out=OUT_DIR          Generate Java source file.
  --js_out=OUT_DIR            Generate JavaScript source.
  --objc_out=OUT_DIR          Generate Objective C header and source.
  --php_out=OUT_DIR           Generate PHP source file.
  --python_out=OUT_DIR        Generate Python source file.
  --ruby_out=OUT_DIR          Generate Ruby source file
  
   @<filename>                proto文件的具体位置

1. 搜索路径参数

表示的是我们要在哪个路径下搜索.proto文件,这个参数既可以用-I指定,也可以使用–proto_path=指定

2. 语言插件参数

即上述的--cpp_out=--python_out=等,protoc支持的语言长达13种,且都是比较常见的。像上面出现的语言参数,说明protoc本身已经内置该语言对应的编译插件,我们无需安装。

而如果上面没出现的,比如--go_out=,就得自己单独安装语言插件,比如--go_out=对应的是protoc-gen-go,安装命令如下:

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest

3. proto文件位置参数

proto文件位置参数即上述的@<filename>参数,指定了我们proto文件的具体位置,如proto1/greeter/greeter.proto

进阶篇

两个易混参数

proto文件(非protoc)有两个易混参数,即packagexx_packagexx指的是你的编译语言,比如你要编程成Go语言,对应的就是go_package

package

package参数针对的是protobuf,是proto文件的命名空间,它的作用是为了避免我们定义的接口,或者message出现冲突。

xx_package

这里以go_package进行举例说明,该参数主要声明Go代码的存放位置,也可以说它解决的是包名问题(因为proto文件编译后会生成一份.pb.go文件,既然是go文件,就有包名问题)

.pb.go常规的存放路径一般是放在同名proto文件下,但也有些人不想这么做,比如他想把所有pb.go文件都存放在一个特定文件夹下,比如上述的pb_go目录,那么他有两种办法:

第一种:

# 修改 --go_out,go_package 保持不变
$ protoc --proto_path=. --go_out=./proto1/pb_go proto1/greeter/greeter.proto

这样会在go_out指定的proto1/pb_go目录下再生成go_package指定的proto1/greeter目录,最终的pb.go文件位于此目录下,且文件包名仍然为greeter。

第二种:

# 修改go_package, go_out保持不变
option go_package="proto1/pb_go";

$ protoc --proto_path=. --go_out=. proto1/greeter/greeter.proto

这样直接在proto1/pb_go目录下生成pb.go文件,文件包名为pb_go

go_package指定的是生成go文件的路径,如果没有显式指定包名(如go_package=“proto1/greeter;packagename”),则包名是路径名的最后一段。而编译时go_out又指定了生成位置,因此最终go文件生成的位置 = go_out指定的目录 + go_package

通常情况下,go_package还是写成此protobuf文件所在项目的路径,最终生成的pb.go文件就和此路径相同。

go_out详细解读

大家在使用时,遇到过这些写法:--go_out=paths=import:.--go_out=paths=source_relative:.,或者--go_out=plugins=grpc:.

--go_out参数是用来指定 protoc-gen-go 插件的工作方式和Go代码的生成位置,而上面的写法正是表明该插件的工作方式。

--go_out主要的两参数为pluginspaths,分别表示生成Go代码所使用的插件,以及生成的Go代码的位置。
--go_out的写法是,参数之间用逗号隔开,最后加上冒号来指定代码的生成位置,比如--go_out=plugins=grpc,paths=import:.

paths参数有两个选项,importssource_relative, 默认为 import,表示按照生成的Go代码的包的全路径去创建目录层级,source_relative 表示按照 proto源文件的目录层级去创建Go代码的目录层级,如果目录已存在则不用创建。

plugins参数有不带grpc和带grpc两种(应该还有其它的,目前知道的有这两种),两者的区别如下,带grpc的会多一些跟gRPC相关的代码,实现gRPC通信.

导入其它proto文件

有时候我们可能有多份proto文件,且每份proto文件不一定是完全独立,它们之间会互相引用,这时候该怎么做呢?

└── proto2
    ├── common.proto
    └── greeter
        └── greeter.proto

greeter.proto内容如下:

syntax = "proto3";

package greeter;

import "proto2/common.proto";

option go_package="proto2/greeter";

service Greeter {
    rpc SayHello (common.Request) returns (common.Response) {}
}

以上述内容为例,假设我们有一个共用的 proto 文件 common.proto,此时 greeter.proto 如果想引用里面的message,就可以使用 import 关键字进行导入。
编译指令如下:

protoc --proto_path=. --go_out=. proto2/greeter/greeter.proto proto2/common.proto

关于protoc-gen-go的多包问题

假设目前的proto文件存放如下:

└── proto
    ├── common.proto
    ├── greeter
    │   └── greeter.proto
    └── user
        └── user.proto

如果你想编译所有proto文件(假设生成Go语言),正常的命令应该是这样的:

protoc --proto_path=. --go_out=. proto/*.proto proto/user/*proto proto/greeter/*proto

但是有的朋友可能会想偷懒,想直接这样:

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

答案是不行的,因为protoc-gen-go不支持这种形式,最终只会编译common.proto。

参考链接:一文了解protoc的使用

 类似资料: