Um cliente Java para uma API WebSockets

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.