1. Wprowadzenie
W tym module nauczysz się tworzyć za pomocą gRPC-Python klienta i serwera, które stanowią podstawę aplikacji do mapowania tras napisanej w Pythonie.
Po ukończeniu tego samouczka będziesz mieć klienta, który łączy się z serwerem zdalnym za pomocą gRPC, aby uzyskać nazwę lub adres pocztowy miejsca znajdującego się pod określonymi współrzędnymi na mapie. W pełni funkcjonalna aplikacja może korzystać z tego modelu klient-serwer, aby wyliczać lub podsumowywać ważne miejsca na trasie.
Usługa jest zdefiniowana w pliku Protocol Buffers, który będzie używany do generowania kodu szablonowego dla klienta i serwera, aby mogły się ze sobą komunikować. Dzięki temu zaoszczędzisz czas i wysiłek potrzebny na wdrożenie tej funkcji.
Wygenerowany kod obsługuje nie tylko złożoność komunikacji między serwerem a klientem, ale także serializację i deserializację danych.
Czego się nauczysz
- Jak używać buforów protokołu do definiowania interfejsu API usługi.
 - Jak utworzyć klienta i serwer oparte na gRPC na podstawie definicji Protocol Buffers za pomocą automatycznego generowania kodu.
 - Znajomość komunikacji klient-serwer z użyciem gRPC.
 
Te warsztaty są przeznaczone dla programistów Pythona, którzy dopiero zaczynają korzystać z gRPC lub chcą sobie przypomnieć podstawy tej technologii, a także dla wszystkich innych osób zainteresowanych tworzeniem systemów rozproszonych. Nie musisz mieć wcześniejszego doświadczenia z gRPC.
2. Zanim zaczniesz
Czego potrzebujesz
- Python w wersji 3.9 lub nowszej. Zalecamy Pythona 3.13. Instrukcje instalacji na poszczególnych platformach znajdziesz w artykule Python Setup and Usage (Konfigurowanie i używanie Pythona). Możesz też zainstalować Pythona, który nie jest częścią systemu, za pomocą narzędzi takich jak uv lub pyenv.
 - pip do instalowania pakietów Pythona.
 - venv do tworzenia wirtualnych środowisk Pythona.
 
Pakiety ensurepip i venv są częścią standardowej biblioteki Pythona i zazwyczaj są dostępne domyślnie.
Niektóre dystrybucje oparte na Debianie (w tym Ubuntu) decydują się jednak na wykluczenie ich podczas redystrybucji Pythona. Aby zainstalować pakiety, uruchom to polecenie:
sudo apt install python3-pip python3-venv
Pobierz kod
Aby ułatwić Ci naukę, w tym ćwiczeniu w Codelabs znajdziesz gotowy szkielet kodu źródłowego, który pomoże Ci zacząć. Poniższe kroki pomogą Ci wypełnić aplikację, w tym wygenerować kod gRPC za pomocą wtyczki kompilatora grpc_tools.protoc Protocol Buffer.
grpc-codelabs
Kod źródłowy szkieletu tego modułu jest dostępny w katalogu codelabs/grpc-python-getting-started/start_here. Jeśli nie chcesz samodzielnie implementować kodu, gotowy kod źródłowy znajdziesz w katalogu completed.
Najpierw utwórz katalog roboczy z ćwiczeniami i przejdź do niego:
mkdir grpc-python-getting-started && cd grpc-python-getting-started
Pobierz i rozpakuj ćwiczenia z programowania:
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
Możesz też pobrać plik ZIP zawierający tylko katalog z instrukcjami i rozpakować go ręcznie.
3. Określ usługę
Pierwszym krokiem jest zdefiniowanie usługi gRPC aplikacji, jej metody RPC oraz typów wiadomości żądania i odpowiedzi za pomocą języka definicji interfejsu Protocol Buffers. Twoja usługa będzie zapewniać:
- Metoda RPC o nazwie 
GetFeature, która jest zaimplementowana na serwerze i wywoływana przez klienta. - Typy wiadomości 
PointiFeatureto struktury danych wymieniane między klientem a serwerem podczas korzystania z metodyGetFeature. Klient podaje współrzędne mapy jakoPointw żądaniuGetFeaturewysyłanym do serwera, a serwer odpowiada, przesyłając odpowiedniFeature, który opisuje wszystko, co znajduje się pod tymi współrzędnymi. 
Ta metoda RPC i jej typy wiadomości będą zdefiniowane w pliku protos/route_guide.proto podanego kodu źródłowego.
Bufory protokołu są powszechnie znane jako protobuf. Więcej informacji o terminologii gRPC znajdziesz w artykule Podstawowe koncepcje, architektura i cykl życia.
Rodzaje wiadomości
W protos/route_guide.proto pliku kodu źródłowego najpierw zdefiniuj Point typ wiadomości. Symbol Point reprezentuje parę współrzędnych szerokości i długości geograficznej na mapie. W tym ćwiczeniu używaj liczb całkowitych jako współrzędnych:
message Point {
  int32 latitude = 1;
  int32 longitude = 2;
}
Numery 1 i 2 to unikalne identyfikatory poszczególnych pól w strukturze message.
Następnie określ Featuretyp wiadomości. Feature używa pola string na nazwę lub adres pocztowy czegoś w lokalizacji określonej przez Point:
message Feature {
  // The name or address of the feature.
  string name = 1;
  // The point where the feature is located.
  Point location = 2;
}
Metoda usługi
Plik route_guide.proto ma strukturę service o nazwie RouteGuide, która definiuje co najmniej 1 metodę udostępnianą przez usługę aplikacji.
Dodaj metodę rpc GetFeature w definicji RouteGuide. Jak wspomnieliśmy wcześniej, ta metoda wyszukuje nazwę lub adres lokalizacji na podstawie podanego zestawu współrzędnych, więc w przypadku danego Point zwraca GetFeature Feature:
service RouteGuide {
  // Definition of the service goes here
  // Obtains the feature at a given position.
  rpc GetFeature(Point) returns (Feature) {}
}
Jest to metoda RPC typu unary: prosta procedura RPC, w której klient wysyła żądanie do serwera i czeka na odpowiedź, podobnie jak w przypadku lokalnego wywołania funkcji.
4. Generowanie kodu klienta i serwera
Następnie wygeneruj kod gRPC dla klienta i serwera z pliku .proto za pomocą kompilatora bufora protokołu.
Do generowania kodu Pythona gRPC stworzyliśmy narzędzie grpcio-tools. Usługa ta obejmuje:
- Zwykły kompilator protoc, który generuje kod Pythona z definicji 
message. - wtyczka gRPC protobuf, która generuje kod Pythona (namiastki klienta i serwera) z definicji 
service; 
Zainstalujemy pakiet Pythona grpcio-tools za pomocą narzędzia pip. Utwórz nowe wirtualne środowisko Pythona (venv), aby odizolować zależności projektu od pakietów systemowych:
python3 -m venv --upgrade-deps .venv
Aby aktywować środowisko wirtualne w powłoce bash/zsh:
source .venv/bin/activate
W przypadku systemu Windows i niestandardowych powłok zobacz tabelę na stronie https://docs.python.org/3/library/venv.html#how-venvs-work.
Następnie zainstaluj grpcio-tools (spowoduje to również zainstalowanie pakietu grpcio):
pip install grpcio-tools
Aby wygenerować kod początkowy w Pythonie, użyj tego polecenia:
python -m grpc_tools.protoc --proto_path=./protos  \
 --python_out=. --pyi_out=. --grpc_python_out=. \
 ./protos/route_guide.proto
Spowoduje to wygenerowanie tych plików dla interfejsów zdefiniowanych w route_guide.proto:
route_guide_pb2.pyzawiera kod dynamicznie tworzący klasy wygenerowane na podstawie definicjimessage.route_guide_pb2.pyito „plik stub” lub „plik wskazówek dotyczących typu” wygenerowany na podstawie definicjimessage. Zawiera tylko sygnatury bez implementacji. Pliki stub mogą być używane przez środowiska IDE, aby zapewnić lepsze autouzupełnianie i wykrywanie błędów.route_guide_pb2_grpc.pyjest generowany na podstawie definicjiservicei zawiera klasy oraz funkcje specyficzne dla gRPC.
Kod gRPC zawiera:
RouteGuideStub, z którego klient gRPC może korzystać do wywoływania wywołań RPC RouteGuide.RouteGuideServicer, który definiuje interfejs implementacji usługiRouteGuide.add_RouteGuideServicer_to_server, która służy do rejestrowaniaRouteGuideServicerna serwerze gRPC.
5. Tworzenie usługi
Najpierw zobaczmy, jak utworzyć RouteGuideserwerRouteGuide. Tworzenie i uruchamianie serwera RouteGuide dzieli się na 2 etapy:
- Wdrożenie interfejsu usługi wygenerowanego na podstawie definicji usługi za pomocą funkcji, które wykonują rzeczywistą „pracę” usługi.
 - Uruchomienie serwera gRPC na określonym porcie, aby nasłuchiwać żądań od klientów i przesyłać odpowiedzi.
 
Początkowy serwer RouteGuide znajdziesz w start_here/route_guide_server.py.
Implementacja RouteGuide
Klasa route_guide_server.py ma klasę RouteGuideServicer, która jest podklasą wygenerowanej klasy route_guide_pb2_grpc.RouteGuideServicer:
# RouteGuideServicer provides an implementation
# of the methods of the RouteGuide service.
class RouteGuideServicer(route_guide_pb2_grpc.RouteGuideServicer):
RouteGuideServicer implementuje wszystkie metody usługi RouteGuide.
Przyjrzyjmy się szczegółowo prostej implementacji RPC. Metoda GetFeature otrzymuje od klienta Point i zwraca odpowiednie informacje o funkcji z bazy danych w 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
Metoda otrzymuje route_guide_pb2.Pointżądanie RPCgrpc.ServicerContext i obiekt grpc.ServicerContext, który zawiera informacje specyficzne dla RPC, takie jak limity czasu. Zwraca odpowiedź route_guide_pb2.Feature.
Uruchamianie serwera
Po zaimplementowaniu wszystkich RouteGuide metod następnym krokiem jest uruchomienie serwera gRPC, aby klienci mogli korzystać z Twojej usługi:
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()
Metoda serwera start() nie blokuje wątku. Do obsługi żądań zostanie utworzony nowy wątek. Wątek wywołujący funkcję server.start() często nie ma w tym czasie nic innego do zrobienia. W takim przypadku możesz wywołać funkcję server.wait_for_termination(), aby prawidłowo zablokować wątek wywołujący do momentu zakończenia działania serwera.
6. Tworzenie klienta
W tej sekcji zajmiemy się tworzeniem klienta dla usługi RouteGuide. Początkowy kod klienta znajdziesz w start_here/route_guide_client.py.
Tworzenie stubu
Aby wywoływać metody usługi, musimy najpierw utworzyć stub.
Tworzymy instancję klasy RouteGuideStub z modułu route_guide_pb2_grpc, wygenerowaną z naszego .proto w pliku route_guide_client.py.
channel = grpc.insecure_channel("localhost:50051")
stub = route_guide_pb2_grpc.RouteGuideStub(channel)
Metody wywoływania usługi
W przypadku metod RPC, które zwracają pojedynczą odpowiedź – znanych jako metody response-unary – gRPC Python obsługuje zarówno synchroniczną (blokującą), jak i asynchroniczną (nieblokującą) semantykę przepływu sterowania.
Proste wywołanie RPC
Najpierw zdefiniujmy Point, za pomocą którego będziemy wywoływać usługę. Powinno to być tak proste, jak utworzenie instancji obiektu z pakietu route_guide_pb2 z kilkoma właściwościami:
point = route_guide_pb2.Point(latitude=412346009, longitude=-744026814)
Synchroniczne wywołanie prostego RPC GetFeature jest prawie tak proste jak wywołanie metody lokalnej. Wywołanie RPC czeka na odpowiedź serwera i zwraca odpowiedź lub zgłasza wyjątek. Możemy wywołać metodę i zobaczyć odpowiedź w ten sposób:
feature = stub.GetFeature(point)
print(feature)
Możesz sprawdzić pola obiektu Feature i wyświetlić wynik żądania:
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. Wypróbuj
Uruchom serwer:
python route_guide_server.py
W innym terminalu ponownie aktywuj środowisko wirtualne, a potem uruchom klienta:
python route_guide_client.py
Zobaczysz dane wyjściowe podobne do tych (sygnatury czasowe zostały pominięte dla przejrzystości):
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. Co dalej?
- Dowiedz się, jak działa gRPC, z artykułów Wprowadzenie do gRPC i Podstawowe pojęcia.
 - Zapoznaj się z samouczkiem dotyczącym podstaw.
 - Zapoznaj się z dokumentacją interfejsu API w Pythonie