В этом блоге вы познакомитесь с основами Rocket, протокола бинарных приложений, который поддерживает реактивные потоки. После введения вы узнаете, как использовать сокет в сочетании с пружинной загрузкой. Наслаждайтесь!
1. Вступление
Rocket – это двоичный протокол, который используется поверх TCP или WebSockets. Rocket – это протокол связи, который охватывает Реактивные принципы . Это означает, что Rocket использует асинхронную связь. Он также подходит для push-уведомлений. Например, при использовании HTTP возникнет необходимость в опросе, чтобы проверить, доступны ли новые сообщения. Это приводит к ненужной нагрузке на сеть. Сокет предоставляет решение для этого. Существует 4 коммуникационные модели, которые можно использовать:
- Запрос-Ответ (поток из 1)
- Выстрели и забудь (ответа нет)
- Поток запросов (поток из многих)
- Канал (двунаправленные потоки)
Сокет расположен на уровне OSI 5/6 и, следовательно, на Прикладном уровне модели TCP/IP.
В следующих разделах вы найдете примеры для каждой модели связи: на стороне сервера, на стороне клиента и модульного теста. Исходный код, используемый в этом посте, конечно же, доступен по адресу GitHub .
2. Справочная документация
Прежде чем приступить к работе, полезно знать, где можно найти интересную документацию. Во время написания этого блога выяснилось, что справочную документацию, примеры и т.д. нелегко найти. Этот список должен дать вам старт, когда вы сделаете свои первые шаги с ракетой.
Всю информацию о протоколе, спецификации, реализациях можно найти на официальном Веб-сайт ракеты .
Платформа Spring поддерживает протокол сокетов.
Справочный раздел Spring Boot для протокола сокета.
Бен Уилкок написал несколько потрясающих блогов о протоколе сокетов. Полный список можно найти по адресу GitHub .
3. Модель Запроса-Ответа
Модель запроса-ответа позволит вам отправить один запрос и получить один ответ в ответ. Первое, что нужно сделать, это настроить базовое приложение Spring Boot. Перейдите на веб-сайт Spring Initializr , добавьте зависимость Сокет и создайте проект, который вы можете открыть в своей любимой среде разработки. При проверке pom вы замечаете, что добавлены зависимости spring-boot-starter-rocket и зависимость реактор-тест . Первый из них позволит включить поддержку сокетов в вашем приложении Spring Boot, второй необходим для целей тестирования.
... org.springframework.boot spring-boot-starter-rsocket io.projectreactor reactor-test test
Исходный код на GitHub разделен на два модуля Maven, один для сервера и один для клиента .
Для обмена информацией между клиентом и сервером вы создаете класс данных Notification , который будет элементом для передачи через RSocket. Класс Уведомление содержит Источник ,/| Пункт назначения и немного свободного Текста . Реализация toString будет использоваться для целей ведения журнала.
public class Notification {
private String source;
private String destination;
private String text;
public Notification() {
super();
}
public Notification(String source, String destination, String text) {
this.source = source;
this.destination = destination;
this.text = text;
}
public String getSource() {
return source;
}
public String getDestination() {
return destination;
}
public String getText() {
return text;
}
@Override
public String toString() {
return "Notification{" +
"source='" + source + '\'' +
", destination='" + destination + '\'' +
", text='" + text + '\'' +
'}';
}
}
3.1 Серверная Часть
Вы создаете контроллер сервера сокетов R и аннотируете его с помощью @Controller . Чтобы создать свой первый пример запроса-ответа сокета, вы просто добавляете метод ответ на запрос который принимает Уведомление , регистрирует полученный Уведомление и возвращает новое Уведомление где вы меняете местами полученный источник и пункт назначения и добавляете к нему простой текст. Чтобы сделать это запросом сокета, вам нужно аннотировать метод с помощью @MessageMapping и дать ему имя, например мой запрос-ответ .
@Controller
public class RsocketServerController {
Logger logger = LoggerFactory.getLogger(RsocketServerController.class);
@MessageMapping("my-request-response")
public Notification requestResponse(Notification notification) {
logger.info("Received notification for my-request-response: " + notification);
return new Notification(notification.getDestination(), notification.getSource(), "In response to: " + notification.getText());
}
}
Чтобы убедиться, что сервер сокетов запущен, вам также необходимо добавить порт в файл application.properties :
spring.rsocket.server.port=7000
Запустите сервер:
$ mvn spring-boot:run
В журнале регистрации вы заметили, что веб-сервер Netty запущен. Netty – это реактивный аналог веб-сервера Jetty.
Netty RSocket started on port(s): 7000
3.2 Клиентская сторона
Клиентская сторона немного сложнее. Вы снова создадите приложение Spring Boot, которое отправит Уведомление сообщение на сервер. Отправка сообщения будет вызвана с помощью http-вызова. Поэтому вы добавляете зависимость spring-boot-starter-web flux в клиент pom . Имейте в виду, что вы не можете использовать spring-boot-starter-web , вам нужно использовать вариант реактивного webflux.
org.springframework.boot spring-boot-starter-webflux
Убедитесь, что вы не определяете порт в application.properties ,
2021-01-02 12:04:58.853 ERROR 19058 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.context.ApplicationContextException: Failed to start bean 'rSocketServerBootstrap'; nested exception is reactor.netty.ChannelBindException: Failed to bind on [0.0.0.0:7000]
...
Caused by: reactor.netty.ChannelBindException: Failed to bind on [0.0.0.0:7000]
Suppressed: java.lang.Exception: #block terminated with an error
...
Вы создаете контроллер R SocketClient и аннотируете его с помощью @RestController . Далее вам нужно создать R Запрашивающий сокет экземпляр для того, чтобы иметь возможность подключиться к серверу сокетов. В методе RequestResponse вы создаете сообщение Уведомление (для простоты использования просто скопируйте класс Уведомление из серверного модуля и убедитесь, что он также присутствует на стороне клиента) и с помощью rSocketRequester экземпляр, вы указываете маршрут, по которому вы хотите отправить сообщение (имя равно имени, указанному в аннотации @MessageMapping на стороне сервера), данные, которые вы хотите отправить, и, наконец, ожидаемый ответ. Ответ будет Моно , что означает, что вы ожидаете один ответ от сервера, и ответ должен быть Уведомлением сообщением. Само сообщение возвращается вызывающему абоненту.
@RestController
public class RsocketClientController {
private static final String CLIENT = "Client";
private static final String SERVER = "Server";
private final RSocketRequester rSocketRequester;
Logger logger = LoggerFactory.getLogger(RsocketClientController.class);
public RsocketClientController(@Autowired RSocketRequester.Builder builder) {
this.rSocketRequester = builder.tcp("localhost", 7000);
}
@GetMapping("/request-response")
public Mono requestResponse() {
Notification notification = new Notification(CLIENT, SERVER, "Test the Request-Response interaction model");
logger.info("Send notification for my-request-response: " + notification);
return rSocketRequester
.route("my-request-response")
.data(notification)
.retrieveMono(Notification.class);
}
}
Запустите как сервер, так и клиент и вызовите URL-адрес:
$ curl http://localhost:8080/request-response
{"source":"Server","destination":"Client","text":"In response to: Test the Request-Response interaction model"}
Как вы можете видеть, возвращается ответ сервера. В журнале регистрации клиента и сервера вы можете проверить отправку и получение сообщений.
Клиент:
Send notification for my-request-response: Notification{source='Client', destination='Server', text='Test the Request-Response interaction model'}
Сервер:
Received notification for my-request-response: Notification{source='Client', destination='Server', text='Test the Request-Response interaction model'}
3.3 Тестовая сторона
Создание теста для кода сервера очень похоже на создание кода клиента. Для настройки соединения необходимо создать R-запрос сокета . Отправка сообщения идентична коду клиента, только на этот раз вы помещаете ответ в переменную результат типа Mono<Уведомление> . Вы можете использовать эту переменную результат в Пошаговом верификаторе для проверки полученного ответа. С помощью Пошагового верификатора вы можете проверить реактивные ответы в своем модульном тесте.
@SpringBootTest
class MyRsocketServerPlanetApplicationTests {
private static final String CLIENT = "Client";
private static final String SERVER = "Server";
private static RSocketRequester rSocketRequester;
@BeforeAll
public static void setupOnce(@Autowired RSocketRequester.Builder builder, @Value("${spring.rsocket.server.port}") Integer port) {
rSocketRequester = builder.tcp("localhost", port);
}
@Test
void testRequestResponse() {
// Send a request message
Mono result = rSocketRequester
.route("my-request-response")
.data(new Notification(CLIENT, SERVER, "Test the Request-Response interaction model"))
.retrieveMono(Notification.class);
// Verify that the response message contains the expected data
StepVerifier
.create(result)
.consumeNextWith(notification -> {
assertThat(notification.getSource()).isEqualTo(SERVER);
assertThat(notification.getDestination()).isEqualTo(CLIENT);
assertThat(notification.getText()).isEqualTo("In response to: Test the Request-Response interaction model");
})
.verifyComplete();
}
}
4. Вывод
Вы изучили основы прикладного протокола сокетов и изучили, как создать сервер, клиент и модульный тест для модели взаимодействия Запрос-ответ. В блоге next вы узнаете, как создать сервер, клиент и модульный тест для оставшихся трех моделей связи.
Оригинал: “https://dev.to/mydeveloperplanet/getting-started-with-rsocket-part-1-442d”