1. Introduction
Dans cet atelier de programmation, vous allez utiliser gRPC-Python pour créer un client et un serveur qui constituent la base d'une application de cartographie d'itinéraires écrite en Python.
À la fin de ce tutoriel, vous disposerez d'un client qui se connecte à un serveur distant à l'aide de gRPC pour obtenir le nom ou l'adresse postale d'un lieu situé à des coordonnées spécifiques sur une carte. Une application complète peut utiliser cette conception client-serveur pour énumérer ou résumer les points d'intérêt le long d'un itinéraire.
Le service est défini dans un fichier Protocol Buffers, qui sera utilisé pour générer du code passe-partout pour le client et le serveur afin qu'ils puissent communiquer entre eux. Vous gagnerez ainsi du temps et des efforts pour implémenter cette fonctionnalité.
Ce code généré gère non seulement les complexités de la communication entre le serveur et le client, mais aussi la sérialisation et la désérialisation des données.
Points abordés
- Utiliser Protocol Buffers pour définir une API de service.
- Comment créer un client et un serveur basés sur gRPC à partir d'une définition Protocol Buffers à l'aide de la génération de code automatisée.
- Comprendre la communication client-serveur avec gRPC.
Cet atelier de programmation s'adresse aux développeurs Python qui découvrent gRPC ou qui souhaitent se rafraîchir la mémoire sur gRPC, ou à toute personne intéressée par la création de systèmes distribués. Aucune expérience préalable avec gRPC n'est requise.
2. Avant de commencer
Prérequis
- Python 3.9 ou version ultérieure. Nous vous recommandons Python 3.13. Pour obtenir des instructions d'installation spécifiques à la plate-forme, consultez Configuration et utilisation de Python. Vous pouvez également installer un Python non système à l'aide d'outils tels que uv ou pyenv.
- pip pour installer les packages Python.
- venv pour créer des environnements virtuels Python.
Les packages ensurepip
et venv
font partie de la bibliothèque standard Python et sont généralement disponibles par défaut.
Toutefois, certaines distributions basées sur Debian (y compris Ubuntu) choisissent de les exclure lors de la redistribution de Python. Pour installer les packages, exécutez la commande suivante :
sudo apt install python3-pip python3-venv
Obtenir le code
Pour faciliter votre apprentissage, cet atelier de programmation propose une structure de code source prédéfinie pour vous aider à démarrer. Les étapes suivantes vous guideront dans la création de l'application, y compris la génération de code gRPC à l'aide du plug-in du compilateur Protocol Buffer grpc_tools.protoc
.
grpc-codelabs
Le code source du scaffold pour cet atelier de programmation est disponible dans le répertoire codelabs/grpc-python-getting-started/start_here. Si vous préférez ne pas implémenter le code vous-même, le code source complet est disponible dans le répertoire completed
.
Commencez par créer le répertoire de travail de l'atelier de programmation et accédez-y :
mkdir grpc-python-getting-started && cd grpc-python-getting-started
Téléchargez et extrayez l'atelier de programmation :
curl -sL https://github.com/grpc-ecosystem/grpc-codelabs/archive/refs/heads/v1.tar.gz \
| tar xvz --strip-components=4 \
grpc-codelabs-1/codelabs/grpc-python-getting-started/start_here
Vous pouvez également télécharger le fichier .zip contenant uniquement le répertoire de l'atelier de programmation et le décompresser manuellement.
3. Définir le service
La première étape consiste à définir le service gRPC de l'application, sa méthode RPC, ainsi que ses types de messages de requête et de réponse à l'aide du langage de définition d'interface Protocol Buffers. Votre service fournira :
- Méthode RPC appelée
GetFeature
que le serveur implémente et que le client appelle. - Les types de messages
Point
etFeature
sont des structures de données échangées entre le client et le serveur lors de l'utilisation de la méthodeGetFeature
. Le client fournit des coordonnées cartographiques sous la forme d'unPoint
dans sa requêteGetFeature
au serveur, et le serveur répond avec unFeature
correspondant qui décrit ce qui se trouve à ces coordonnées.
Cette méthode RPC et ses types de messages seront tous définis dans le fichier protos/route_guide.proto
du code source fourni.
Les Protocol Buffers sont communément appelés "protobuf". Pour en savoir plus sur la terminologie gRPC, consultez Concepts fondamentaux, architecture et cycle de vie de gRPC.
Types de messages
Dans le fichier protos/route_guide.proto
du code source, définissez d'abord le type de message Point
. Un Point
représente une paire de coordonnées (latitude et longitude) sur une carte. Pour cet atelier de programmation, utilisez des nombres entiers pour les coordonnées :
message Point {
int32 latitude = 1;
int32 longitude = 2;
}
Les nombres 1
et 2
sont des ID uniques pour chacun des champs de la structure message
.
Ensuite, définissez le type de message Feature
. Un Feature
utilise un champ string
pour le nom ou l'adresse postale d'un élément à un emplacement spécifié par un Point
:
message Feature {
// The name or address of the feature.
string name = 1;
// The point where the feature is located.
Point location = 2;
}
Méthode de service
Le fichier route_guide.proto
possède une structure service
nommée RouteGuide
qui définit une ou plusieurs méthodes fournies par le service de l'application.
Ajoutez la méthode rpc
GetFeature
dans la définition RouteGuide
. Comme expliqué précédemment, cette méthode recherche le nom ou l'adresse d'un lieu à partir d'un ensemble de coordonnées donné. Par conséquent, faites en sorte que GetFeature
renvoie un Feature
pour un Point
donné :
service RouteGuide {
// Definition of the service goes here
// Obtains the feature at a given position.
rpc GetFeature(Point) returns (Feature) {}
}
Il s'agit d'une méthode RPC unaire : un RPC simple où le client envoie une requête au serveur et attend une réponse, comme pour un appel de fonction local.
4. Générer le code client et serveur
Ensuite, générez le code gRPC standard pour le client et le serveur à partir du fichier .proto
à l'aide du compilateur de tampons de protocole.
Pour la génération de code Python gRPC, nous avons créé grpcio-tools. Il inclut les éléments suivants :
- Le compilateur protoc standard qui génère du code Python à partir des définitions
message
. - Plug-in protobuf gRPC qui génère du code Python (stubs client et serveur) à partir des définitions
service
.
Nous allons installer le package Python grpcio-tools
à l'aide de pip. Créons un environnement virtuel Python (venv) pour isoler les dépendances de votre projet des packages système :
python3 -m venv --upgrade-deps .venv
Pour activer l'environnement virtuel dans le shell bash/zsh :
source .venv/bin/activate
Pour Windows et les shells non standards, consultez le tableau à l'adresse https://docs.python.org/3/library/venv.html#how-venvs-work.
Ensuite, installez grpcio-tools (cela installe également le package grpcio) :
pip install grpcio-tools
Utilisez la commande suivante pour générer le code standard Python :
python -m grpc_tools.protoc --proto_path=./protos \
--python_out=. --pyi_out=. --grpc_python_out=. \
./protos/route_guide.proto
Cette opération génère les fichiers suivants pour les interfaces que nous avons définies dans route_guide.proto
:
route_guide_pb2.py
contient le code qui crée dynamiquement des classes générées à partir des définitionsmessage
.route_guide_pb2.pyi
est un fichier stub ou un fichier d'indication de type généré à partir des définitionsmessage
. Il ne contient que les signatures sans implémentation. Les fichiers de stub peuvent être utilisés par les IDE pour améliorer l'autocomplétion et la détection des erreurs.route_guide_pb2_grpc.py
est généré à partir des définitionsservice
et contient des classes et des fonctions spécifiques à gRPC.
Le code spécifique à gRPC contient :
RouteGuideStub
, qui peut être utilisé par un client gRPC pour appeler les RPC RouteGuide.RouteGuideServicer
, qui définit l'interface pour les implémentations du serviceRouteGuide
.- La fonction
add_RouteGuideServicer_to_server
est utilisée pour enregistrer unRouteGuideServicer
sur un serveur gRPC.
5. Créer le service
Commençons par voir comment créer un serveur RouteGuide
. La création et l'exécution d'un serveur RouteGuide
se décomposent en deux tâches :
- Implémenter l'interface de service générée à partir de notre définition de service avec des fonctions qui effectuent le "travail" réel du service.
- Exécuter un serveur gRPC sur un port spécifique pour écouter les requêtes des clients et transmettre les réponses.
Vous trouverez le serveur RouteGuide
initial dans start_here/route_guide_server.py
.
Implémenter RouteGuide
route_guide_server.py
comporte une classe RouteGuideServicer
qui est une sous-classe de la classe générée route_guide_pb2_grpc.RouteGuideServicer
:
# RouteGuideServicer provides an implementation
# of the methods of the RouteGuide service.
class RouteGuideServicer(route_guide_pb2_grpc.RouteGuideServicer):
RouteGuideServicer
implémente toutes les méthodes de service RouteGuide
.
Examinons en détail une implémentation RPC simple. La méthode GetFeature
obtient un Point
du client et renvoie les informations correspondantes sur les caractéristiques de sa base de données dans Feature
.
def GetFeature(self, request, context):
feature = get_feature(self.db, request)
if feature is None:
return route_guide_pb2.Feature(name="", location=request)
else:
return feature
La méthode reçoit une requête route_guide_pb2.Point
pour le RPC et un objet grpc.ServicerContext
qui fournit des informations spécifiques au RPC, telles que les limites de délai d'attente. Il renvoie une réponse route_guide_pb2.Feature
.
Démarrer le serveur
Une fois que vous avez implémenté toutes les méthodes RouteGuide
, l'étape suivante consiste à démarrer un serveur gRPC afin que les clients puissent réellement utiliser votre service :
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
route_guide_pb2_grpc.add_RouteGuideServicer_to_server(
RouteGuideServicer(),
server,
)
listen_addr = "localhost:50051"
server.add_insecure_port(listen_addr)
print(f"Starting server on {listen_addr}")
server.start()
server.wait_for_termination()
La méthode start()
du serveur n'est pas bloquante. Un nouveau thread sera instancié pour gérer les requêtes. Le thread appelant server.start()
n'aura souvent aucune autre tâche à effectuer en attendant. Dans ce cas, vous pouvez appeler server.wait_for_termination()
pour bloquer proprement le thread appelant jusqu'à ce que le serveur se termine.
6. Créer le client
Dans cette section, nous allons créer un client pour notre service RouteGuide
. Vous pouvez consulter le code client initial dans start_here/route_guide_client.py
.
Créer un stub
Pour appeler des méthodes de service, nous devons d'abord créer un stub.
Nous instancions la classe RouteGuideStub
du module route_guide_pb2_grpc
, générée à partir de notre .proto
dans le fichier route_guide_client.py
.
channel = grpc.insecure_channel("localhost:50051")
stub = route_guide_pb2_grpc.RouteGuideStub(channel)
Appeler des méthodes de service
Pour les méthodes RPC qui renvoient une seule réponse (appelées méthodes response-unary), gRPC Python est compatible avec les sémantiques de flux de contrôle synchrone (bloquant) et asynchrone (non bloquant).
RPC simple
Commençons par définir un Point
pour appeler le service. Il suffit d'instancier un objet à partir du package route_guide_pb2
avec certaines propriétés :
point = route_guide_pb2.Point(latitude=412346009, longitude=-744026814)
Un appel synchrone au RPC simple GetFeature
est presque aussi simple que l'appel d'une méthode locale. L'appel RPC attend la réponse du serveur et renvoie une réponse ou génère une exception. Nous pouvons appeler la méthode et voir la réponse comme suit :
feature = stub.GetFeature(point)
print(feature)
Vous pouvez inspecter les champs de l'objet Feature et afficher le résultat de la requête :
if feature.name:
print(f"Feature called '{feature.name}' at {format_point(feature.location)}")
else:
print(f"Found no feature at at {format_point(feature.location)}")
7. Essayer
Exécutez le serveur :
python route_guide_server.py
Depuis un autre terminal, activez à nouveau l'environnement virtuel, puis exécutez le client :
python route_guide_client.py
Un résultat semblable à celui-ci s'affiche (les codes temporels sont omis pour plus de clarté) :
name: "16 Old Brook Lane, Warwick, NY 10990, USA" location { latitude: 412346009 longitude: -744026814 } Feature called '16 Old Brook Lane, Warwick, NY 10990, USA' at latitude: 412346009, longitude: -744026814
8. Étape suivante
- Découvrez comment fonctionne gRPC dans Présentation de gRPC et Concepts de base.
- Suivez le tutoriel sur les principes de base.
- Explorez la documentation de référence de l'API Python.