Let’s start with a very simple example. Suppose you want to define a message format to represent search requests, where each search request has three items:

  • A query string
  • The specific results page you are interested in
  • And the number of results per page

Below is the.proto file used to define message types

syntax = "proto3";

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}Copy the code
  • The first line indicates that version 3 of the protocol is used. If you don’t write this,protobufI think you’re usingprotobuf2This line must be the first line and must not be preceded by a comment
  • SearchRequestThis message defines three fields (name/value pairs) that each message contains, each with a name and a type

Field Type Description

In the above example, all fields are of basic type: two integers (page_number and result_per_page) and a string (query). These fields can also be compound types, including enumerations and other message types

Field label

Each field in the message definition has a unique numbered label that identifies the field in the message binary format and cannot be modified once the message is in use

Note:

  • Labels with values in the range 1 to 15 require one byte to encode, including the identification number and field type
  • Labels in the range 16 to 2047 occupy two bytes.

Therefore, you should reserve tags 1 through 15 for very frequent message elements. Remember to leave some room for frequent elements that may be added in the future.

The minimum tag is 1, the maximum tag is 536870911, i.e. 2^ 29-1, and 19000-19999 is reserved for protobuf system, cannot use these

Field Rule Description

There are two types

  • Singular: A regular message should have zero or one of these fields
  • Repeated: A message that complies with a rule can have zero or any of these fields in a repeated orderproto3In, duplicate fields of basic types are compressed by default

Add more message types

You can add multiple message types to a single.proto file, for example

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}

message SearchResponse {
 ...
}Copy the code

Add comments

You can add comments to.proto files using //. For example,

message SearchRequest {
  string query = 1;
  int32 page_number = 2;  // Which page number do we want?
  int32 result_per_page = 3;  // Number of results to return per page.
}Copy the code

Preserve fields (field modification or deletion solutions)

When the message type is updated or deleted, the labels of the modified fields may cause incorrect data if they continue to be used. In this case, you need to reserve the labels to prevent conflicts with the data of the old version. (When using JSON serialization, the field name may also have this problem.) Generally speaking, it is equivalent to an APP that has been launched using interface A. At this time, if the server wants to modify the data format of interface A, it can only add an interface, and the address of interface A must not be used

case

message Foo {
  reserved 2.15.9 to 11;
  reserved "foo"."bar";
}Copy the code

This means that 2,15,9,10,11, “foo”, “bar” cannot be used again

.protoWhat does the file generate?

When compiling the.proto file, the compiler generates the code for the language you choose, and you need to use the message types described in the file, including getting and setting field values, serializing the message to the output stream, and parsing the message from the input stream

  • For PHP, the compiler generates a class for each message that describes the message
  • For C ++, the compiler starts from each.protogenerate.hand.ccFile, and specify a class for each message type described in your file
  • For Java, the compiler generates a class for each message type.javaFile, and a special Builder class for creating instances of the message class
  • Python is a little different in that the Python compiler generates a module that contains.protoStatic descriptor for each message type, and then use metaclass to create the necessary Python data access classes at run time
  • For Go, the compiler generates a typed.pb.go file for each message type in the file
  • For Ruby, the compiler generates a.rb file containing the Ruby module containing the message type
  • For JavaNano, the compiler output is similar to Java, but without the Builder class
  • For Objective-C, the compiler starts from each.protoTo generate apbobjc.handpbobjc.mFile, which has a class for each message type described in the file
  • For C#, the compiler starts from each.protoTo generate a.csFile, which has a class for each message type described in the file