Синтаксис Protobuf

gRPC

1. Основные характеристики

  • файл с.protoВ качестве суффикса файла операторы, отличные от определений структуры, заканчиваются точкой с запятой.
  • Определения структуры могут содержать: сообщение, сервис, перечисление.
  • сообщение определяет структуру, сервис определяет метод
  • Точка с запятой в конце определения метода rpc необязательна.
  • Сообщение названо в верблюжьем регистре, а имена полей разделены строчными буквами и символами подчеркивания.
  • Имена типов перечислений написаны в верблюжьем регистре, а имена полей разделены прописными буквами и символами подчеркивания.
  • Имена сервисов и методов rpc едины в имени верблюжьего регистра.
enum GenderType {
    SECRET = 0;
    FEMALE = 1;
    MALE = 2;
}

// 人
message Person {
    int64 id = 1;
    string name = 2;
    GenderType gender = 3;
    string number = 4;
}

2. Правила поля

Формат поля

Формат поля: модификатор уточнения | тип данных | имя поля | = | значение кодировки поля | [значение поля по умолчанию]

модификатор квалификации

К модификаторам квалификации относятся: обязательные, необязательные, повторяющиеся.

  • Обязательное: указывает, что это обязательное поле
  • Необязательно: представляет необязательное поле. Для получателя, если необязательное поле может быть распознано, оно будет обработано соответствующим образом, если оно не может быть распознано, поле будет проигнорировано.
  • Повторяется: указывает, что поле может содержать от 0 до N элементов. Свойства такие же, как и необязательные, но каждое из них может содержать несколько значений. Это можно рассматривать как передачу массива значений

тип данных

Protobuf определяет набор основных типов данных:

Тип данных Protobuf описывать Пакет
bool логический тип 1 байт
double 64-битная с плавающей запятой N
float 32-битное число с плавающей запятой N
int32 32-битное целое число N
uint32 беззнаковое 32-битное целое N
int64 64-битное целое число N
uint64 64-битное целое число без знака N
$int32 32-битное целое, более эффективное для обработки отрицательных чисел N
$int64 64-битное целое, более эффективное для обработки отрицательных чисел N
fixed32 32-битное целое число без знака 4
fixed64 64-битное целое число без знака 8
$fixed32 32-битное целое число, может более эффективно обрабатывать отрицательные числа 4
$fixed64 64-битные целые числа, которые могут более эффективно обрабатывать отрицательные числа. 8
string Может обрабатывать только символы ASCII N
bytes Используется для обработки многобайтовых языковых символов, таких как китайский. N
enum Может содержать определяемый пользователем тип перечисления uint32. N(uiint32)
message Может содержать определяемый пользователем тип сообщения N
  • N означает, что упакованные байты не фиксированы, а в соответствии с размером или длиной данных
  • Что касается разницы между fiex32 и int32: эффективность упаковки fixed32 выше, чем у int32, но обычно он использует больше места, чем int32.

Имя поля

  • Именование имен полей почти такое же, как именование переменных в таких языках, как C и Java.
  • protobuf рекомендует, чтобы поля назывались в верблюжьем регистре и разделялись символами подчеркивания.

значение кодировки поля

  • С помощью этого значения две взаимодействующие стороны могут идентифицировать поля друг друга. Для одного и того же значения кодировки модификатор квалификации и тип данных должны быть одинаковыми. Диапазон значений значения кодирования: 1 ~ 2^32 (4294967296)
  • Среди них самыми высокими являются время кодирования и пространственная эффективность от 1 до 15. Чем больше значение кодирования, тем ниже время кодирования и пространственная эффективность.
  • 1900 ~ 2000 Значение кодирования - это зарезервированное значение в системе Google Protobuf, и рекомендуется не использовать его в проекте.

Значение поля по умолчанию

  • При передаче данных для требуемого типа данных, если пользователь не устанавливает значение, значение по умолчанию используется для передачи партнеру.

3. Как определить услугу

  • Если вы хотите использовать тип сообщения в системе RPC, вы можете.protoИнтерфейс службы RPC определен в файле, и компилятор буфера протокола сгенерирует код интерфейса службы в соответствии с выбранными языками.
  • Сгенерированный код интерфейса используется как соглашение между клиентом и сервером.Сервер должен реализовать все определенные методы интерфейса, и клиент напрямую вызывает одноименный метод, чтобы инициировать запрос к серверу (даже если никакие параметры не указаны). требуется в бизнесе, должно быть указано сообщение запроса, которое обычно определяется как пустое сообщение)

Например, если вы хотите определить службу RPC и иметь метод, который получает SearchRequest и возвращает SearchResponse, вы можете.protoВ файле сделаны следующие определения:

service SearchService {
	rpc Search(SearchRequest) returns (SearchResponse) {}
}

4. Как определить сообщение

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

5. Добавьте больше типов сообщений

Файл .proto может определять несколько типов сообщений, которые обычно используются для одновременного определения нескольких связанных сообщений, например, для определения поискового запроса и ответных сообщений в одном и том же файле .proto:

syntax = "proto3" // 声明使用的 protobuf 版本

message SearchRequest {
	string query = 1; // 查询字符串
	int32 page_number = 2;
	int32 result_per_page = 3;
}

message SearchResponse {

}

6. Как использовать другие сообщения

сообщение поддерживает вложенное использование в качестве типа поля в другом сообщении

message SearchResponse {
	repeated Result results = 1;
}

message Result {
	string url = 1;
	string title = 2;
	repeated string snippets = 3;
}

7. Использование вложенности сообщений

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

Внутренне объявленные имена типов сообщений могут использоваться только непосредственно внутри:

message SearchResponse {
	message Result {
		string url = 1;
		string title = 2;
		repeated string snippets = 3;
	}
	repeated Result results = 1;
}

Кроме того, возможно несколько уровней вложенности:

message Outer {
	message A {
		message Inner {
			int64 ival = 1;
			bool booly = 2;
		}
	}
	message B {
		message Inner {
			int64 ival = 1;
			bool booly = 2;
		}
	}
}

8. Тип карты PROTO3

  • proto3 поддерживает объявление типа карты

  • Типы ключей и значений могут быть встроенными типами или пользовательскими типами сообщений.

  • Поле не поддерживает повторяющийся атрибут

    map<key_type, value_type>map_field = N;
    
    message Project {...}
    map<string, Project>projects = 1;
    

9. Компиляция файла .proto

  • Чтобы сгенерировать Java, Python, Go, Ruby и другой код через определенный файл .proto, вам необходимо установить протокол компилятора.
  • Формат кода, генерируемый разными языками с помощью компилятора protobuf, отличается:
    • Go: Создайте файл .pb.go, каждый тип сообщения соответствует структуре
    • Java: создание файла Java, каждое сообщение соответствует классу, а специальный класс Builder используется для создания интерфейса сообщений.
    • ......

10. Определение импорта импорта

  • Типы, объявленные в других файлах описаний, можно импортировать с помощью оператора import.

  • Файл интерфейса protobuf может импортировать нужные файлы через импорт, например:import "example.proto"

  • Компилятор protobuf будет искать импортированные файлы в каталоге, указанном параметром -I/ --proto_path Если этот параметр не указан, по умолчанию он будет искать в текущем каталоге.

11. Использование пакетов

Используйте package, чтобы объявить имя пакета в прото-файле, чтобы избежать конфликтов имен:

syntax = "proto3"
package foo.bar
message Open {...}

В других определениях формата сообщения вы можете использовать имя пакета + имя сообщения для использования типа, например:

message Foo {
	...
	foo.bar.Open open = 1;
	...
}

В разных языках определения имен пакетов по-разному влияют на код, сгенерированный после компиляции:

  • Go: использовать имя пакета в качестве имени пакета по умолчанию, если не указана опция go_package.
  • Java: используйте имя пакета в качестве имени пакета по умолчанию, если не указана опция go_package.
  • Python: пакет игнорируется