1. Введение
HTTP (протокол передачи гипертекста) — это протокол запроса-ответа без сохранения состояния. Его простой дизайн делает его очень масштабируемым, но неподходящим и неэффективным для высокоинтерактивных веб-приложений в реальном времени из-за объема служебных данных, которые необходимо передавать вместе с каждым запросом/ответом.
Поскольку HTTP является синхронным, а приложения реального времени должны быть асинхронными, любые решения, такие как опрос или длительный опрос ( Comet ), как правило, сложны и неэффективны.
Чтобы решить указанную выше проблему, нам нужен основанный на стандартах, двунаправленный и полнодуплексный протокол, который мог бы использоваться как серверами, так и клиентами, и это привело к введению API JSR 356 — в этой статье мы покажу пример его использования.
2. Настройка
Давайте включим зависимости Spring WebSocket в наш проект:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
Мы всегда можем получить последние версии зависимостей от Maven Central для spring-websocket и spring-messaging .
3. ТОМП
Stream Text-Oriented Messaging Protocol (STOMP) — это простой, совместимый проводной формат, который позволяет клиенту и серверам обмениваться данными практически со всеми брокерами сообщений. Это альтернатива AMQP (протокол расширенной очереди сообщений) и JMS (служба обмена сообщениями Java).
STOMP определяет протокол для взаимодействия клиент/сервер с использованием семантики обмена сообщениями. Семантика находится поверх WebSockets и определяет фреймы, которые сопоставляются с фреймами WebSockets.
Использование STOMP дает нам гибкость для разработки клиентов и серверов на разных языках программирования. В этом текущем примере мы будем использовать STOMP для обмена сообщениями между клиентом и сервером.
4. Веб-сокет-сервер
Подробнее о построении серверов WebSocket можно прочитать в этой статье .
5. Веб-сокет-клиент
Для связи с сервером WebSocket клиент должен инициировать соединение WebSocket, отправив HTTP-запрос на сервер с правильно установленным заголовком Upgrade :
GET ws://websocket.example.com/ HTTP/1.1
Origin: http://example.com
Connection: Upgrade
Host: websocket.example.com
Upgrade: websocket
Обратите внимание, что URL-адреса веб-сокетов используют схемы ws
и wss
, вторая означает безопасные веб-сокеты.
Сервер отвечает, отправляя в ответ заголовок Upgrade
, если включена поддержка WebSockets.
HTTP/1.1 101 WebSocket Protocol Handshake
Date: Wed, 16 Oct 2013 10:07:34 GMT
Connection: Upgrade
Upgrade: WebSocket
Как только этот процесс (также известный как рукопожатие WebSocket) завершен, первоначальное соединение HTTP заменяется соединением WebSocket поверх того же соединения TCP/IP, после чего обе стороны могут обмениваться данными.
Это подключение на стороне клиента инициируется экземпляром WebSocketStompClient .
5.1. WebSocketStompClient
_ ``
Как описано в разделе 3, сначала нам нужно установить соединение WebSocket, и это делается с помощью класса WebSocketClient .
WebSocketClient можно настроить с помощью :
StandardWebSocketClient
предоставляется любой реализацией JSR-356, такой как Tyrus.JettyWebSocketClient
предоставляется собственным API WebSocket Jetty 9+.- Любая реализация Spring
WebSocketClient
Мы будем использовать StandardWebSocketClient
, реализацию WebSocketClient
в нашем примере:
WebSocketClient client = new StandardWebSocketClient();
WebSocketStompClient stompClient = new WebSocketStompClient(client);
stompClient.setMessageConverter(new MappingJackson2MessageConverter());
StompSessionHandler sessionHandler = new MyStompSessionHandler();
stompClient.connect(URL, sessionHandler);
new Scanner(System.in).nextLine(); // Don't close immediately.
По умолчанию WebSocketStompClient
поддерживает SimpleMessageConverter
. Поскольку мы имеем дело с сообщениями JSON, мы устанавливаем конвертер сообщений на MappingJackson2MessageConverter
, чтобы преобразовать полезную нагрузку JSON в объект.
При подключении к конечной точке мы передаем экземпляр StompSessionHandler
, который обрабатывает такие события, как afterConnected
и handleFrame
.
Если наш сервер поддерживает SockJs, мы можем модифицировать клиент для использования SockJsClient
вместо StandardWebSocketClient.
5.2. StompSessionHandler
_ ``
Мы можем использовать StompSession
для подписки на тему WebSocket. Это можно сделать, создав экземпляр StompSessionHandlerAdapter
, который, в свою очередь, реализует StompSessionHandler
.
StompSessionHandler предоставляет события жизненного
цикла для сеанса STOMP. События включают обратный вызов при установлении сеанса и уведомления в случае сбоев.
Как только клиент WebSocket подключается к конечной точке, StompSessionHandler
получает уведомление и вызывается метод afterConnected ()
, где мы используем StompSession
для подписки на тему:
@Override
public void afterConnected(
StompSession session, StompHeaders connectedHeaders) {
session.subscribe("/topic/messages", this);
session.send("/app/chat", getSampleMessage());
}
@Override
public void handleFrame(StompHeaders headers, Object payload) {
Message msg = (Message) payload;
logger.info("Received : " + msg.getText()+ " from : " + msg.getFrom());
}
Убедитесь, что сервер WebSocket запущен и работает клиент, в консоли будет выведено сообщение:
INFO o.b.w.client.MyStompSessionHandler - New session established : 53b993eb-7ad6-4470-dd80-c4cfdab7f2ba
INFO o.b.w.client.MyStompSessionHandler - Subscribed to /topic/messages
INFO o.b.w.client.MyStompSessionHandler - Message sent to websocket server
INFO o.b.w.client.MyStompSessionHandler - Received : Howdy!! from : Nicky
6. Заключение
В этом кратком руководстве мы реализовали клиент WebSocket на основе Spring.
Полную реализацию можно найти на GitHub .