Um cliente Java para uma API WebSockets
1. Introdução
HTTP (Hypertext Transfer Protocol) é um protocolo de solicitação-resposta sem estado. Seu design simples o torna muito escalável, mas inadequado e ineficiente para aplicativos da Web em tempo real altamente interativos, devido à quantidade de sobrecarga que precisa ser transmitida juntamente com cada solicitação / resposta.
Como o HTTP é síncrono e os aplicativos em tempo real precisam ser assíncronos, quaisquer soluções como polling ou long polling (Comet) tendem a ser complicadas e ineficientes.
Para resolver o problema especificado acima, precisamos de um protocolo baseado em padrões, bidirecional e full-duplex que possa ser usado por servidores e clientes, e isso levou à introdução deJSR 356 API - neste artigo, vamos mostrar um exemplo de uso dele.
2. Configuração
Vamos incluir as dependências do Spring WebSocket em nosso projeto:
org.springframework
spring-websocket
5.0.5.RELEASE
org.springframework
spring-messaging
5.0.5.RELEASE
Sempre podemos obter as versões mais recentes das dependências do Maven Central paraspring-websocketespring-messaging.
3. STOMP
O STOMP (Stream Text-Oriented Messaging Protocol) é um formato de conexão interoperável simples que permite que clientes e servidores se comuniquem com quase todos os intermediários de mensagens. É uma alternativa ao AMQP (Advanced Message Queuing Protocol) e JMS (Java Messaging Service).
O STOMP define um protocolo para o cliente / servidor se comunicar usando a semântica de mensagens. A semântica está no topo dos WebSockets e define os quadros mapeados nos quadros do WebSockets.
O uso do STOMP nos dá a flexibilidade de desenvolver clientes e servidores em diferentes linguagens de programação. Neste exemplo atual, usaremos o STOMP para enviar mensagens entre cliente e servidor.
4. Servidor WebSocket
Você pode ler mais sobre como construir servidores WebSocket nestearticle.
5. Cliente WebSocket
Para se comunicar com o servidor WebSocket, o cliente deve iniciar a conexão WebSocket enviando uma solicitação HTTP a um servidor com um cabeçalhoUpgrade definido corretamente:
GET ws://websocket.example.com/ HTTP/1.1
Origin: http://example.com
Connection: Upgrade
Host: websocket.example.com
Upgrade: websocket
Observe que os URLs do WebSocket usam os esquemaswsewss, o segundo significa WebSockets seguros.
O servidor responde enviando o cabeçalhoUpgrade na resposta se o suporte a WebSockets estiver habilitado.
HTTP/1.1 101 WebSocket Protocol Handshake
Date: Wed, 16 Oct 2013 10:07:34 GMT
Connection: Upgrade
Upgrade: WebSocket
Quando esse processo (também conhecido como handshake do WebSocket) é concluído, a conexão HTTP inicial é substituída pela conexão do WebSocket sobre a mesma conexão TCP / IP, após a qual as partes podem compartilhar dados.
Esta conexão do lado do cliente é iniciada pela instânciaWebSocketStompClient.
5.1. OWebSocketStompClient
Conforme descrito na seção 3, primeiro precisamos estabelecer uma conexão WebSocket, e isso é feito usando a classeWebSocketClient.
OWebSocketClient pode ser configurado usando:
-
StandardWebSocketClient fornecido por qualquer implementação JSR-356 como Tyrus
-
JettyWebSocketClient fornecido pela API WebSocket nativa Jetty 9+
-
Qualquer implementação deWebSocketClient do Spring
UsaremosStandardWebSocketClient, uma implementação deWebSocketClient em nosso exemplo:
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.
Por padrão,WebSocketStompClient oferece suporte aSimpleMessageConverter. Como estamos lidando com mensagens JSON, configuramos o conversor de mensagem paraMappingJackson2MessageConverter para converter a carga útil JSON em objeto.
Ao conectar a um ponto de extremidade, passamos uma instância deStompSessionHandler, que trata os eventos comoafterConnectedehandleFrame.
Se nosso servidor tiver suporte para SockJs, podemos modificar o cliente para usarSockJsClient em vez deStandardWebSocketClient.
5.2. OStompSessionHandler
Podemos usarStompSession para assinar um tópico WebSocket. Isso pode ser feito criando uma instância deStompSessionHandlerAdapter que, por sua vez, implementaStompSessionHandler.
UmStompSessionHandler fornece eventos de ciclo de vida para uma sessão STOMP. Os eventos incluem um retorno de chamada quando a sessão é estabelecida e notificações em caso de falhas.
Assim que o cliente WebSocket se conecta ao endpoint,StompSessionHandler é notificado e o métodoafterConnected() é chamado, onde usamosStompSession para assinar o tópico:
@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());
}
Certifique-se de que o servidor WebSocket esteja em execução e executando o cliente, a mensagem será exibida no console:
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. Conclusão
Neste tutorial rápido, implementamos um cliente WebSocket baseado em Spring.
A implementação completa pode ser encontradaover on GitHub.