gRPC клиент. Попробуй на вкус клиент/сервер на gRPC

от автора

   В моем случае я использую многомодульный проект, но можно создать отдельный проект. Структура проекта будет примерно следующей: 

Структура проекта
Структура проекта

Мы реализуем основные методы, которые были описаны в .proto. Обратите внимание, что serverStream разобьется на 2 метода, о чем я расскажу дальше.

Эти методы мы реализуем в ходе статьи
Эти методы мы реализуем в ходе статьи

Как и в прошлой статье нам необходимо добавить плагин для генерации .proto файлов. Если возникли сложности, можно посмотреть код примера в репозитории.

Для того, чтобы отправлять вызовы на удаленный сервер, нам необходимо создать клиента. gRPC предоставляет несколько возможностей создания клиента — это BlockingStub и Stub. В чем отличие этих “заглушек”? BlockingStub — создает новую блокирующую заглушку, которая поддерживает вызовы унарного и потокового вывода (unary and streaming output calls, офф. док.), Stub — cоздает новую асинхронную заглушку, которая поддерживает все типы вызовов. Мы рассмотрим оба варианта заглушек. Для создании заглушки нам необходим Channel. Channel — если коротко, то это виртуальное соединение с концептуальной конечной точкой для выполнения RPC. Для создания Channel нам потребуется хост и порт. 

// Access a service running on the local machine on port 7777 String target = "localhost:7777";  // Create a communication channel to the server, known as a Channel. Channels are thread-safe // and reusable. It is common to create channels at the beginning of your application and reuse // them until the application shuts down. ManagedChannel channel = ManagedChannelBuilder.forTarget(target)   // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid   // needing certificates.   .usePlaintext()   .build();

Затем мы можем создать newBlockingStub и newStub (создаем через Channel и ManagedChannel для примера)

// 'channel' here is a Channel, not a ManagedChannel,  // so it is not this code's responsibility to // shut it down. // Passing Channels to code makes code easier to test  // and makes it easier to reuse Channels. blockingStub = ProfileServiceGrpc.newBlockingStub(channel); asyncStub = ProfileServiceGrpc.newStub(ManagedChannelBuilder.forAddress(HOST, PORT).usePlaintext().build());

Вся подготовительная работа закончена. Теперь можно реализовать методы интерфейса. Начнем с самого простого — getCurrentProfile. Для вызова сервера, нам нужно лишь вызвать метод заглушки и передать в нее необходимые параметры.

Реализация getCurrentProfile
Реализация getCurrentProfile

  Я использую стандартный main метод, где создаю объект интерфейса и вызываю необходимые методы. В целом ничего не мешает написать тесты, но для меня быстрее и проще написать main.

Main
Main

  Теперь если вызвать getCurrentProfile, то мы получим ответ профиля с именем “test” (сервер из прошлой статьи). 

Отлично, с базовым методом разобрались. Давайте теперь рассмотрим clientStream. Отличия от предыдущего метода минимальные. Нам лишь нужно передавать сообщения на сервер не единожды, как было в прошлом примере, а постоянно. Если обратиться к логам сервера, то можно заметить, что он получает сообщения от клиента и логирует их. 

Server Stream. Для реализации получения потоковых данных с сервера, можно использовать различные заглушки. Если использовать блокирующую заглушку, то мы дождемся всех ответов сервера и затем обработаем результат. Если использовать асинхронную заглушку, то мы будем обрабатывать результат сразу после того как сервер нам ответит. 

// Блокирующая и асинхронная заглушки private final ProfileServiceGrpc.ProfileServiceBlockingStub blockingStub; private final ProfileServiceGrpc.ProfileServiceStub asyncStub;
// Создание заглушек в конструкторе public GrpcProfileClientImpl() {     // Create a communication channel to the server, known as a Channel. Channels are thread-safe     // and reusable. It is common to create channels at the beginning of your application and reuse     // them until the application shuts down.     ManagedChannel channel = ManagedChannelBuilder.forTarget(TARGET)             // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid             // needing certificates.             .usePlaintext()             .build();     blockingStub = ProfileServiceGrpc.newBlockingStub(channel);     asyncStub = ProfileServiceGrpc.newStub(channel); }

Для принятия ответов, используя BlockingStub нам потребуется Iterator, куда сервер будет складывать ответы. И потом, пробежавшись по нему, мы увидим то, что нам прислал сервер. 

А вот для не блокирующего принятия сообщений нам потребуется передать StreamObserver, в который сервер будет передавать ответы.

Не блокирующее получение ответов от сервера
Не блокирующее получение ответов от сервера

Так как у нас получение происходит асинхронно, я добавляю CountDownLatch с await, для того что бы текущий поток подождал ответов от сервера. 

И последний вариант клиент серверного взаимодействия — biDirectionalStream. Нам снова потребуется реализовать StreamObserver в который клиент будет передавать сообщения и получать ответы от сервера.

Если все запустить и проверить, то по логам клиента и сервера можно заметить, что сообщение передаются и наш клиент работает корректно. 

Подведем итоги

Мы написали клиент, для рассмотренного в прошлой статье сервера на gRPC. Рассмотрели и реализовали основные варианты клиент серверного взаимодействия с использованием gRPC. А вы используете gRPC для клиент серверного общения? Почему вы выбрали gRPC? 

   В прошлой статье мы разобрали, как писать сервер на gRPC. И протестировали его с помощью BloomRPC. Теперь, давайте разберем как пишется клиент. И попробуем отправлять запросы с клиента на сервер. Это будет наш первый шаг к созданию микросервисов на грпц. 

ссылка на оригинал статьи https://habr.com/ru/post/566504/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *