GERBELOTBARILLON.COM

Parce qu'il faut toujours un commencement...

Protocol Buffer

Informations Générales


Protocol Buffer est un moyen simple, rapide et efficace de réaliser des échanges de messages entre applications ou microservices. Chaque fichier .proto, composant le message, débute par la déclaration de syntaxe que le compilateur doit respecter. Aujourd'hui c'est la version 3. Ensuite chaque message est une structure composée de plusieurs lignes de 3 champs :

Par exemple

            syntax = "proto3";

            message MyMessage {
               int32 id = 1;
               string first_name = 2;
               bool validated = 3;
            }
            

Installation


Pour Windows
Téléchargez l'archive sur le site https://github.com/google/protobuf/releases et extrayez le contenu dans le répertoire C:\proto3. Dans la liste prenez le fichier au format de votre OS (soit par exemple le fichier protoc-x.xx.x-win64.zip pour un Windows 64 bits). Il vous faut ensuite ajouter le chemin c:\proto3\bin à votre variable d'environnement PATH.

Pour Linux
Prenez la même adresse de GitHub que pour l'installation de la version Windows mais cette fois choisissez le fichier zip correspondant à votre version de linux (par exemple protoc-x.xx.x-linux-x86_64.zip).
curl -OL https://github.com/google/protobuf/releases/protoc-x.xx.x-linux-x86_64.zip
unzip protoc-x.xx.x-linux-x86_64.zip -d proto3
sudo mv proto3/bin/* /usr/local/bin
sudo mv proto3/include/* /usr/local/include

Pour Mac OS
Il suffit d'ouvrir un terminal et de saisir brew install protobuf

Types de variables


Il existe un certain nombre de déclarations pour les types scalaires : int32, int64, uint32, uint64, double, float, sint32, sint64, fixed32, fixed64, sfixed32, sfixed64. Ils désignent des valeurs flottantes, en simple ou double précision, des entiers en 32 ou 64 bits, des entiers signés ou non signés.

Généralement, pour des raisons de simplicité, nous serons amenés à utiliser essentiellement les types int32, float (32 bits) ou double (64 bits).

bool pour un booléen qui sera true ou false.
string pour une chaine de caractère qui sera toujours encodée en UTF-8 ou ASCII-7 bits. Il n'y a pas d'autres représentations de chaines.
bytes pour représenter une séquence d'octets.

Par défaut une variable dispose d'une valeur zéro qui sera :

Les énumérations sont déclarées par le mot clé enum. Un enum doit commencer par le tag 0. Une énumération va créer un type à l'intérieur d'un message. Il ne restera qu'à définir une variable de ce type dans le message.

syntax = "proto3";

message Personne {
   int32 age = 1;

   enum EyeColor {
      UNKNOWN_COLOR = 0; // valeur par défaut
      GREEN_EYE = 1;
      BLUE_EYE = 2;
   }
   // Utilisation du type énuméré comme type dans le message
   EyeColor couleur_des_yeux = 2;
}

Les Tags


Ce qui est important dans la définition du message en ProtoBuf est le Tag (sous-entendu le Tag Number). C'est un nombre qui peut aller de 1 (pas zéro) jusqu'à 2^29 - 1. L'intervalle 19000 à 19999 ne doit pas être utilisé car réservé à Google...

Les Tags numérotés de 1 à 15 utilient un octet et sont à réserver aux champs les plus fréquemment peuplés par votre application. Les tags numérotés de 16 à 2047 occupent quant à eux 2 octets.

Les champs répétition


Il suffit de marquer la définition du tag par le mot-clé repeated. Cela va enregistrer le fait que les éléments qui suivent peuvent être répétés et du même type.

syntax = "proto3";

message Personne {
   string name = 1;
   int32 age = 2;
   bool is_adult = 3;
   repeated phone_number = 4;
}

Structure des messages


Un fichier peut contenir autant de messages que l'on souhaite, soit de messages déclarés les uns à la suite des autres, soit inclus les uns dans les autres. Le fait de déclarer un message induit la génération d'un type qui est exploitable automatiquement.

syntax = "proto3";

message PremierMessage {
   int age = 1;
   string name = 2;

   // Le type Date provient du message déclaré à la suite de ce PremierMessage
   Date Anniversaire = 3;

   // Déclaration d'un message à l'intérieur d'un autre message
   message Address {
      string address1 = 1;
      string address2 = 2;
      string zipcode = 3;
      string country = 4;
   }
   // Utilisation du type Address provenant du message déclaré encapsulé dans PremierMessage
   repeated Address addresses = 4; // Le numéro du tag est celui qui vient en séquence dans le message PremierMessage
}

message Date {
   int year = 1;
   int month = 2;
   int day = 3;
}
Il suffit de marquer la définition du tag par le mot-clé repeated. Cela va enregistrer le fait que les éléments qui suivent peuvent être répétés et du même type.
syntax = "proto3";

message Personne {
   string name = 1;
   int32 age = 2;
   bool is_adult = 3;
   repeated phone_number = 4;
}

Si des messages ont dékà été écrits dans d'autres fichiers, il suffit de les importer par la commande import "chemin-complet-du-fichier-à-importer"; en prenant garde à craiment appeler l'import avec le chemin pleinement qualifé qui mène à votre fichier .proto que vous souhaitez importer.

Si vous souhaitez structurer votre code, vous pouvez utiliser la notion de packages pour les fichiers que vous importez. Cela permettra d'éviter par exemple que plusieurs imports portent le même nom et génère des conflits. Il suffit de noter package nom-du-package; dans le message pouvant être importé et de l'utiliser avec son nom de package depuis le message qui en a besoin nom-du-package.type-de-message variable.

syntax = "proto3";

import "mon-message.proto";

message TestMessage {
   int32 age = 1;

   mon-message.Date anniversaire;
}
Et dans le fichier importé mon-message.proto nous déclarons la notion de package :
syntax = "proto3";

package mon-message;

message Date {
   int32 jour = 1;
   int32 mois = 2;
   int32 annee = 3;
}

Protobuf et les langages


Langage Go

Références


Site des développeurs ProtoBuf chez Google : https://developers.google.com/protocol-buffers