Статья для понимания использования protoc

gRPC
Статья для понимания использования protoc

предисловие

Как мы упоминали ранее, gRPC использует protobuf для сериализации и десериализации, а также использует его в качестве языка определения интерфейсов.protocяма!

Примечание. В этой статье используется версия протокола 3.7.1.

Установить

# 安装
$ brew install protoc

# 查看版本
$ protoc --version
libprotoc 3.7.1

Основы

Основы в основном для всех, чтобы быть знакомыми сprotocНекоторые основные параметры и общее использование, структура проекта выглядит следующим образом:

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

Содержимое файла welcomer.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 --proto_path=. --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. Параметры пути поиска

Первым важным параметром является搜索路径参数, который показан выше-IPATH, --proto_path=PATH.它表示的是我们要在哪个路径下搜索.protoфайл, этот параметр можно использовать либо-Iуказано, вы также можете использовать--proto_path=указано.

Если этот параметр не указан, по умолчанию используетсятекущий путьИскать в разделе, кроме того, этот параметр также может быть указан несколько раз, что также означает, что мы можем указатьнесколько путейискать.

Например, следующие три команды имеют одинаковое значение.

# Makefile
GOPATH:=$(shell go env GOPATH)

# proto1 相关指令
.PHONY: proto1
path1:
	protoc --go_out=. proto1/greeter/greeter.proto
path2:
	protoc -I. --go_out=. proto1/greeter/greeter.proto # 点号表示当前路径,注意-I参数没有等于号
path3:
	protoc --proto_path=. --go_out=. proto1/greeter/greeter.proto

Примечание: я привык писать команды компиляции protoc в Makefile, во-первых, его легко найти, а во-вторых, просто выполнить.

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

# 指定版本
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.3.0

Если вы хотите узнать больше о плагинах для компиляции языка, нажмите здесьофициальная документация protobufПроводить проверку.

3. параметры расположения файла proto

Параметр местоположения прото-файла указан выше.@<filename>Параметр указывает конкретное расположение нашего прото-файла, напримерproto1/greeter/greeter.proto.

Передовой

Два смешиваемых параметра

файлы proto (не protoc) имеют два запутанных параметра, а именноpackageа такжеxx_package, xx относится к вашему скомпилированному языку.Например, если вы хотите программировать на языке Go, соответствующийgo_package.

package

packageПараметр для protobuf, который является пространством имен файла proto.Его функция состоит в том, чтобы избежать определенного нами интерфейса или конфликта сообщений.

Чтобы взять маленький каштан, скажем, у меня естьA.protoа такжеB.protoДва документа, как показано ниже

# A.proto
message UserInfo {
    uint32 uid = 1;
    string name = 2;
}

# B.proto
message UserInfo {
    uint32 uid = 1;
    string name = 2;
    uint32 age = 3;
    string work = 4;
}

Как и выше, два документа имеют один в то же времяUserInfoсообщение, в это время, если мне нужно сослаться на файл B в файле A, если пакет не указан, я не могу различить, должен ли быть передан AUserInfoВсе еще настроен на Б.

xx_package

здесь сgo_packageНапример, этот параметр в основном декларирует место хранения кода Go, а также можно сказать, что он решает проблему имени пакета (поскольку прото-файл будет генерировать копию после компиляции.pb.goфайл, так как это файл go, есть проблема с именем пакета)

.pb.goОбычный путь хранения обычно размещается под одноименным прото-файлом, но некоторые люди не хотят этого делать, например, он хочет поставить все.pb.goФайлы хранятся в определенной папке, такой как вышеpb_go, то у него есть два варианта:

Первый:

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

这样生成的pb文件在 pb_go/proto1/greeter 目录下,文件目录有点冗余,不过pb文件的包名仍然是 greeter

Второй:

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

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

这样生成的pb文件在 pb_go 目录下,pb文件的包名为 pb_go

Кроме того,xx_packageНа самом деле есть два способа объявить, первый — объявить в файле, вы его видели; второй — объявить в командной строке, формат объявления следующий:M${PROTO_FILE}=${GO_IMPORT_PATH}.

В настоящее время официальный документ рекомендует объявлять его в файле, цель состоит в том, чтобы сократить длину инструкции протокола, и я лично рекомендую этот метод.

Ну я полагаю, что по вышеприведенным примерам уже можно примерно понятьpackageа такжеxx_packageРазница, опять же, была указана в официальной документации,packageа такжеxx_packageЭти два не связаны и принадлежат к разным категориям.

--go_out подробная интерпретация

Предположительно, при его использовании вы должны были столкнуться с такими надписями:--go_out=paths=import:.,--go_out=paths=source_relative:.,или--go_out=plugins=grpc:..

Что значит написать это?

Итак, нам нужно знать,--go_outПараметры используются для указания того, как работает плагин protoc-gen-go и где генерируется код Go, а приведенное выше описание указывает, как работает плагин.

--go_outДвумя основными параметрами являютсяpluginsа такжеpaths, которые соответственно представляют подключаемый модуль, используемый для создания кода Go, и расположение сгенерированного кода Go.--go_outСпособ написания таков, что параметры разделяются запятыми, и, наконец, добавляется двоеточие, чтобы указать место генерации кода, например--go_out=plugins=grpc,paths=import:..

pathsЕсть два варианта параметра:importа такжеsource_relativeЗначение по умолчанию для импорта, выраженное в виде полного пути к пакету Go для генерации кода для создания иерархии каталогов, source_relative, выраженное в видеИерархия каталогов исходных файлов протоЧтобы создать иерархию каталогов кода Go, не создавайте каталог, если он уже существует.

Например:

option go_package="proto1/pb_go";

# 指令1:paths为import,pb文件最终在 pb_go 目录下
$ protoc --proto_path=. --go_out=. proto1/greeter/greeter_v2.proto
$ protoc --proto_path=. --go_out=paths=import:. proto1/greeter/greeter_v2.proto

# 指令2:paths为source_relative,pb文件最终在 proto1/greeter 目录下
$ protoc --proto_path=. --go_out=paths=source_relative:. proto1/greeter/greeter_v2.proto

pluginsСуществует два типа параметров: без grpc и с grpc (должны быть и другие, в настоящее время известно, что они имеют эти два), разница между ними заключается в следующем: с grpc будет больше кода, связанного с gRPC для реализации связи gRPC:

image.png

Импортировать другие прото-файлы

Иногда у нас может быть несколько прото-файлов, и каждый прото-файл не обязательно полностью независим, и они будут ссылаться друг на друга.Что нам делать в это время?

└── 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) {}
}

Взяв приведенный выше контент в качестве примера, предположим, что у нас есть общий прото-файл common.proto.В настоящее время, если Greeter.proto хочет сослаться на сообщение в нем, его можно импортировать с помощью ключевого слова import.

Инструкции по компиляции следующие:

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

Проблема с несколькими пакетами на protoc-gen-go

Предположим, что текущий прото-файл хранится следующим образом:

└── proto
    ├── common.proto
    ├── greeter
    │   └── greeter.proto
    └── user
        └── user.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 и упоминаются некоторые проблемы, с которыми часто сталкивается protoc.Эти проблемы в основном связаны с расположением создания pb-файла и определением имени пакета.Рекомендуется делать больше и больше практиковаться. Исходный код этой статьи можно найти по адресуМой Гитхабпроверить

Эта статья была изменена несколько раз, и мне больно ее писать.Если вы найдете ее полезной, пожалуйста, поставьте мне лайк!

Я Ян Ган, прошу обратить внимание на мой публичный аккаунт言淦Coding, ваши лайки и внимание - самая большая мотивация для моего творчества! !

Справочная документация

Практика использования функции импорта Protobuf в проектах Go