gRPC est un framework RPC (Remoto Protocol Call) open source moderne et performant qui peut être exécuté dans n'importe quel environnement. Il présente l'avantage de pouvoir sérialiser les données à l'aide de tampons de protocole et de réaliser une communication à haut débit. Il est compatible avec différentes langues et plates-formes, et le streaming bidirectionnel utilisant http / 2 est possible. Vous pouvez simplement définir des services (données et fonctions à communiquer) à l'aide de Protocol Buffers et clarifier les spécifications de l'API.
git: k-washi/stereophonic-Sound-System/proto
L'article gRPC de Golang versin peut être trouvé dans GRPC commençant par Golang.
Cette section décrit comment utiliser gRPC pour répondre à une demande d'un client avec la position (x, y, z) d'un objet approprié calculé par le serveur. À l'origine, c'est un système qui génère un son stéréophonique en fonction de la position du personnage, et a été créé pour transmettre des informations de position.
pip install grpcio-tools==1.26.0
Définissez les positions x, y, z comme Pos dans le fichier .proto comme indiqué ci-dessous. Ensuite, Position devient un protocole (convention de communication) comprenant des informations de localisation. D'autre part, le protocole Msg est défini comme résultat de l'émission d'un message demandant des informations de localisation au côté serveur ou de l'émission d'informations de localisation. De plus, PositionReq et PositionPub sont définis comme des fonctions utilisées pour la communication. PositionReq est une fonction qui envoie Msg au serveur et reçoit des informations de Position du serveur, et PositionPub est une fonction qui envoie des informations de Position au serveur et reçoit Msg. Dans cet article, nous expliquerons à l'aide d'un exemple utilisant PositionReq.
proto/position.proto
syntax = "proto3";
package posXYZ;
option go_package="posXYZpb";
message Pos {
float x = 1;
float y = 2;
float z = 3;
}
//client streaming
message Position{
Pos position = 1;
int32 status = 2;
string msg = 3;
}
message Msg{
int32 status = 1;
string msg = 2;
}
service PositionService{
rpc PositionReq(Msg) returns (Position) {};
rpc PositionPub(Position) returns (Msg) {};
}
Comme décrit dans l'article gRPC de Golang versin gRPC commençant par Golang, même s'il est converti en un tampon de protocole pour golang, il ressemble à cet article. Même si vous convertissez en tampon de protocole pour python, la conversion sera basée sur la définition de protocole ci-dessus. En convertissant vers ce tampon de protocole, la structure de chaque message défini dans chaque langue et le document de définition (programme) comprenant la fonction de service sont émis.
Python peut être converti en exécutant le programme suivant.
proto/codegen.py
from grpc.tools import protoc
protoc.main(
(
'',
'-I.',
'--python_out=.',
'--grpc_python_out=.',
'./proto/position.proto',
)
)
python ./proto/codegen.py
Suite à la commande ci-dessus, position_pb2.py qui définit le message défini dans le fichier de protocole et position_pb2_grpc.py qui définit la fonction utilisée pour la communication gRPC sont générés.
Ici, implémentez un serveur qui reçoit le message de demande et émet Position (informations de localisation). L'information de position émise ici est une position qui tourne tout en maintenant une distance de 1 m de (x, y, z) = (0, 0, 0).
Concernant configInit pour les paramètres non liés à gRPC et logger pour la journalisation, mon article précédent Parameter setting by python configparser, [Python logging Veuillez vous référer à Comment utiliser le module.
La classe PositionServer surcharge le PositionServerServer défini dans position_pb2_grpc.py et définit la fonction PositionReq qui renvoie des informations de position en réponse à une demande. Cette valeur de retour, Position, utilise celle définie dans position_pb2.py. En outre, cette classe définit également des fonctions qui stockent et produisent des informations de localisation x, y et z, et gère les informations de localisation.
La classe Server est une classe qui résume le traitement effectué par le côté serveur de gRPC. Par conséquent, il a une instance de la classe PosotionServer comme variable. La fonction de démarrage définit le processus pour démarrer le serveur gRPC et la fonction d'arrêt définit le processus pour arrêter le serveur gRPC. Étant donné que ces processus de démarrage et d'arrêt sont des phrases fixes, le flux de base ne change dans aucun programme.
Dans le processus principal, le serveur est ouvert en exécutant la fonction de démarrage et le processus côté serveur de gRPC est terminé. Ici, afin de changer les informations de localisation toutes les heures, les informations de localisation émises par posServer.pubPos (x, y, z) sont écrasées.
proto/server.py
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
# ------------
from utils.config import configInit
Conf = configInit()
logger = Conf.setLogger(__name__)
# ------------
#grpc
import grpc
from proto.position_pb2 import *
from proto import position_pb2_grpc
# ------------
from concurrent import futures
class PositionService(position_pb2_grpc.PositinServiceServicer):
def __init__(self):
self.x = 1.
self.y = 0.
self.z = 0.
def PositionReq(self, request, context):
try:
is_success = 0
except:
is_success = -1
return Position(
position = Pos(
x = self.x, y = self.y, z = self.z
),
status = is_success,
msg = "character position"
)
def pubPos(self, x, y, z):
self.x, self.y, self.z = x, y, z
def getPos(self, x, y, z):
return self.x, self.y, self.z
class Server():
def __init__(self):
self.posServer = PositionService()
def start(self):
self.server = grpc.server(futures.ThreadPoolExecutor(max_workers=3))
position_pb2_grpc.add_PositinServiceServicer_to_server(
self.posServer, self.server
)
self.server.add_insecure_port(Conf.PosServer)
self.server.start()
logger.info("Start server {0}".format(Conf.PosServer))
def stop(self):
self.server.stop(0)
if __name__ == "__main__":
import time
import numpy as np
server = Server()
server.start()
z = 0.
azimuth = 0.
aziShift = 5* np.pi / 180.
def azi2pos(azimuth):
x = np.cos(azimuth)
y = np.sin(azimuth)
return x, y
try:
while True:
time.sleep(0.1)
azimuth += aziShift
x,y = azi2pos(azimuth)
server.posServer.pubPos(x,y,z)
except Exception as e:
logger.critical(e)
server.stop()
L'implémentation côté client est implémentée dans la classe posClient. Démarrez le traitement du client avec la fonction ouverte. Notez que position_pb2_grpc.PositinServiceStub contient les fonctions que le client exécute. Par conséquent, dans la fonction posRequest, Msg peut être envoyé par la fonction self.stub.PositionReq et les informations du serveur peuvent être obtenues comme valeur de retour. Après cela, chaque fois que vous exécutez posRequest () dans le processus principal, vous pouvez communiquer avec le côté serveur et obtenir les informations de localisation.
proto/client.py
mport os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
# ------------
from utils.config import configInit
Conf = configInit()
logger = Conf.setLogger(__name__)
# ------------
#grpc
import grpc
from proto.position_pb2 import *
from proto import position_pb2_grpc
class posClient():
def __init__(self):
self.x = 0.
self.y = 0.
self.z = 0.
def posRequest(self):
request = Msg(
status = 0,
msg = "request pos"
)
res = self.stub.PositionReq(request)
if res.status == 0:
logger.info("PositionRes {0}, {1}, x:{2}, y:{3}, z:{4}".format(res.status, res.msg, res.position.x, res.position.y, res.position.z))
self.x, self.y, self.z = res.position.x, res.position.y, res.position.z
return True
logger.error("Position Response Error")
return False
def open(self):
self.channel = grpc.insecure_channel(Conf.PosClient)
self.stub = position_pb2_grpc.PositinServiceStub(self.channel)
logger.info("Open position client channel: {0}".format(Conf.PosClient))
def close(self):
self.channel.close()
def getPos(self):
return self.x, self.y, self.z
if __name__ == "__main__":
import time
posCl = posClient()
posCl.open()
while True:
time.sleep(1)
try:
ok = posCl.posRequest()
if ok:
x, y, z = posCl.getPos()
logger.info("{0}, {1}, {2}".format(x, y, z))
except Exception as e:
logger.error("client error {0}".format(e))
posCl.close()
Avec ce qui précède, les informations de localisation peuvent être échangées avec gRPC par python. Je pense que gRPC sera une technologie qui sera utilisée dans de nombreuses situations à l'avenir, car elle présente des avantages tels que faciliter la création de microservices écrits dans plusieurs langues. Veuillez essayer.
Recommended Posts