1. Введение
В этой лабораторной работе вы будете использовать gRPC-Python для создания клиента и сервера, которые составят основу приложения для отображения маршрутов, написанного на Python.
К концу руководства у вас будет клиент, который подключается к удалённому серверу с помощью gRPC для получения названия или почтового адреса объекта, расположенного в определённых координатах на карте. Полноценное приложение может использовать эту клиент-серверную архитектуру для перечисления или суммирования точек интереса на маршруте.
Служба определена в файле Protocol Buffers, который будет использоваться для генерации шаблонного кода для клиента и сервера, чтобы они могли взаимодействовать друг с другом, экономя ваше время и усилия при реализации этой функциональности.
Сгенерированный код учитывает не только сложности взаимодействия между сервером и клиентом, но также сериализацию и десериализацию данных.
Чему вы научитесь
- Как использовать Protocol Buffers для определения API сервиса.
 - Как создать клиент и сервер на основе gRPC из определения Protocol Buffers с использованием автоматической генерации кода.
 - Понимание клиент-серверного взаимодействия с помощью gRPC.
 
Эта практическая работа предназначена для разработчиков Python, впервые использующих gRPC или желающих освежить свои знания, а также для всех, кто интересуется разработкой распределённых систем. Опыт работы с gRPC не требуется.
2. Прежде чем начать
Что вам понадобится
- Python 3.9 или выше. Мы рекомендуем Python 3.13. Инструкции по установке для конкретных платформ см. в разделе «Настройка и использование Python» . Также можно установить несистемный Python с помощью таких инструментов, как uv или pyenv .
 - pip для установки пакетов Python.
 - venv для создания виртуальных сред Python.
 
 Пакеты ensurepip и venv являются частью стандартной библиотеки Python и обычно доступны по умолчанию.
Однако некоторые дистрибутивы на базе Debian (включая Ubuntu) исключают их при распространении Python. Чтобы установить пакеты, выполните:
sudo apt install python3-pip python3-venv
Получить код
 Для упрощения обучения эта лабораторная работа предлагает готовый исходный код, который поможет вам начать работу. Следующие шаги помогут вам завершить приложение, включая генерацию кода gRPC с помощью плагина компилятора буфера протокола grpc_tools.protoc .
grpc-codelabs
 Исходный код scaffold для этой лабораторной работы доступен в каталоге codelabs/grpc-python-getting-started/start_here . Если вы предпочитаете не реализовывать код самостоятельно, готовый исходный код доступен в каталоге completed .
Сначала создайте рабочий каталог codelab и перейдите в него:
mkdir grpc-python-getting-started && cd grpc-python-getting-started
Загрузите и распакуйте кодовую лабораторию:
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
Кроме того, вы можете загрузить .zip-файл, содержащий только каталог codelab, и вручную распаковать его.
3. Определите услугу
Первым шагом будет определение службы gRPC приложения, её метода RPC и типов сообщений запросов и ответов с помощью языка определения интерфейсов Protocol Buffers . Ваша служба будет предоставлять:
-  Метод RPC, называемый 
GetFeature, который реализует сервер и вызывает клиент. -  Типы сообщений 
PointиFeatureпредставляют собой структуры данных, которыми обмениваются клиент и сервер при использовании методаGetFeature. Клиент предоставляет координаты карты в качествеPointв запросеGetFeatureк серверу, а сервер отвечает соответствующимFeature, описывающим объект, находящийся в этих координатах. 
 Этот метод RPC и его типы сообщений будут определены в файле protos/route_guide.proto предоставленного исходного кода.
Буферы протоколов обычно называются protobuf. Подробнее о терминологии gRPC см. в разделе «Основные концепции, архитектура и жизненный цикл gRPC».
Типы сообщений
 В файле protos/route_guide.proto исходного кода сначала определите тип сообщения Point . Point представляет собой пару координат (широта-долгота) на карте. В этой практической работе используйте целые числа в качестве координат:
message Point {
  int32 latitude = 1;
  int32 longitude = 2;
}
 Цифры 1 и 2 — это уникальные идентификационные номера для каждого из полей в структуре message .
 Затем определите тип сообщения Feature . Feature использует string поле для имени или почтового адреса объекта, расположенного в месте, указанном Point :
message Feature {
  // The name or address of the feature.
  string name = 1;
  // The point where the feature is located.
  Point location = 2;
}
Метод обслуживания
 Файл route_guide.proto имеет структуру service с именем RouteGuide , которая определяет один или несколько методов, предоставляемых службой приложения.
 Добавьте метод rpc GetFeature в определение RouteGuide . Как объяснялось ранее, этот метод ищет название или адрес местоположения по заданному набору координат, поэтому GetFeature должен возвращать Feature для заданной Point :
service RouteGuide {
  // Definition of the service goes here
  // Obtains the feature at a given position.
  rpc GetFeature(Point) returns (Feature) {}
}
Это унарный метод RPC: простой RPC , при котором клиент отправляет запрос серверу и ждет ответа, как при локальном вызове функции.
4. Сгенерируйте клиентский и серверный код.
 Затем сгенерируйте шаблонный код gRPC для клиента и сервера из файла .proto , используя компилятор буфера протокола.
Для генерации кода gRPC Python мы создали пакет grpcio-tools . Он включает в себя:
-  Обычный компилятор протоколов , который генерирует код Python из определений 
message. -  Плагин gRPC protobuf, который генерирует код Python (клиентские и серверные заглушки) из определений 
service. 
 Мы установим пакет Python grpcio-tools с помощью pip. Создадим новую виртуальную среду Python (venv), чтобы изолировать зависимости вашего проекта от системных пакетов:
python3 -m venv --upgrade-deps .venv
Чтобы активировать виртуальную среду в оболочке bash/zsh:
source .venv/bin/activate
Для Windows и нестандартных оболочек см. таблицу по адресу https://docs.python.org/3/library/venv.html#how-venvs-work .
Далее установите grpcio-tools (это также установит пакет grpcio ):
pip install grpcio-tools
Используйте следующую команду для генерации шаблонного кода Python:
python -m grpc_tools.protoc --proto_path=./protos  \
 --python_out=. --pyi_out=. --grpc_python_out=. \
 ./protos/route_guide.proto
Это приведет к созданию следующих файлов для интерфейсов, которые мы определили в route_guide.proto :
-  
route_guide_pb2.pyсодержит код , который динамически создает классы , генерируемые из определенийmessage. -  
route_guide_pb2.pyi— это «файл-заглушка» или «файл подсказок типа», созданный на основе определенийmessage. Он содержит только сигнатуры без реализации. Файлы-заглушки могут использоваться IDE для улучшения автодополнения и обнаружения ошибок. -  
route_guide_pb2_grpc.pyсоздается на основе определенийserviceи содержит специфичные для gRPC классы и функции. 
Специфический для gRPC код содержит:
-  
RouteGuideStub, который может использоваться клиентом gRPC для вызова RPC RouteGuide. -  
RouteGuideServicer, который определяет интерфейс для реализаций службыRouteGuide. -  Функция 
add_RouteGuideServicer_to_server, которая используется для регистрацииRouteGuideServicerна сервере gRPC . 
5. Создайте услугу
 Сначала давайте рассмотрим, как создать сервер RouteGuide . Создание и запуск сервера RouteGuide делится на два этапа:
- Реализация интерфейса сервиса, созданного на основе определения нашего сервиса, с функциями, которые выполняют фактическую «работу» сервиса.
 - Запуск сервера gRPC на определенном порту для прослушивания запросов от клиентов и передачи ответов.
 
 Первоначальный сервер RouteGuide можно найти в start_here/route_guide_server.py .
Реализовать RouteGuide
 route_guide_server.py имеет класс RouteGuideServicer , который является подклассом сгенерированного класса route_guide_pb2_grpc.RouteGuideServicer : 
# RouteGuideServicer provides an implementation
# of the methods of the RouteGuide service.
class RouteGuideServicer(route_guide_pb2_grpc.RouteGuideServicer):
RouteGuideServicer реализует все методы службы RouteGuide .
 Давайте подробно рассмотрим простую реализацию RPC. Метод GetFeature получает Point от клиента и возвращает соответствующую информацию о функции из своей базы данных в 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
Методу передаётся запрос route_guide_pb2.Point для RPC и объект grpc.ServicerContext , предоставляющий информацию, специфичную для RPC, например, ограничения по времени ожидания. Метод возвращает ответ route_guide_pb2.Feature .
Запуск сервера
 После реализации всех методов RouteGuide следующим шагом будет запуск сервера gRPC, чтобы клиенты могли использовать вашу службу: 
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()
Метод server.start start() не блокирует выполнение. Для обработки запросов будет создан новый поток. Поток, вызывающий server.start() часто не будет занят другими делами. В этом случае можно вызвать server.wait_for_termination() , чтобы аккуратно заблокировать вызывающий поток до завершения работы сервера. 
6. Создайте клиента
 В этом разделе мы рассмотрим создание клиента для нашего сервиса RouteGuide . Исходный код клиента можно найти в start_here/route_guide_client.py .
Создать заглушку
Для вызова методов службы сначала нужно создать заглушку .
 Мы создаем экземпляр класса RouteGuideStub модуля route_guide_pb2_grpc , сгенерированного из нашего .proto внутри файла route_guide_client.py . 
channel = grpc.insecure_channel("localhost:50051")
stub = route_guide_pb2_grpc.RouteGuideStub(channel)
Вызов методов обслуживания
Для методов RPC, которые возвращают один ответ (известных как унарные методы ответа), gRPC Python поддерживает как синхронную (блокирующую), так и асинхронную (неблокирующую) семантику потока управления.
Простой RPC
 Сначала определим Point для вызова сервиса. Это должно быть так же просто, как создание экземпляра объекта из пакета route_guide_pb2 с некоторыми свойствами: 
point = route_guide_pb2.Point(latitude=412346009, longitude=-744026814)
Синхронный вызов простого RPC GetFeature почти так же прост, как вызов локального метода. RPC-вызов ожидает ответа сервера и либо возвращает ответ, либо генерирует исключение. Мы можем вызвать метод и увидеть ответ следующим образом: 
feature = stub.GetFeature(point)
print(feature)
Вы можете проверить поля объекта Feature и вывести результат запроса:
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. Попробуйте
Запускаем сервер:
python route_guide_server.py
С другого терминала снова активируйте виртуальную среду, затем запустите клиент:
python route_guide_client.py
Вы увидите примерно такой вывод, при этом временные метки опущены для ясности:
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. Что дальше?
- Узнайте, как работает gRPC, изучив раздел «Введение в gRPC» и «Основные концепции».
 - Проработайте базовый учебник
 - Изучите справочник по API Python