Ein Java-Client für eine WebSockets-API

1. Einleitung

HTTP (Hypertext Transfer Protocol) ist ein zustandsloses Request-Response-Protokoll. Aufgrund seines einfachen Designs ist es sehr skalierbar, aber ungeeignet und ineffizient für hochgradig interaktive Echtzeit-Webanwendungen, da bei jeder Anforderung / Antwort ein Overhead erforderlich ist.

Da HTTP synchron ist und Echtzeitanwendungen asynchron sein müssen, sind Lösungen wie Polling oder Long Polling (Comet) in der Regel kompliziert und ineffizient.

Um das oben angegebene Problem zu lösen, benötigen wir ein standardbasiertes, bidirektionales und Vollduplex-Protokoll, das sowohl von Servern als auch von Clients verwendet werden kann. Dies führte zur Einführung der JSR 356-API. Ich werde ein Beispiel für die Verwendung zeigen.

2. Setup

Nehmen wir die Spring WebSocket-Abhängigkeiten in unser Projekt auf:

 org.springframework spring-websocket 5.2.2.RELEASE   org.springframework spring-messaging 5.2.2.RELEASE 

Wir können immer die neuesten Versionen der Abhängigkeiten von Maven Central für Spring-Websocket und Spring-Messaging erhalten.

3. STOMP

Das Stream Text-Oriented Messaging Protocol (STOMP) ist ein einfaches, interoperables Drahtformat, mit dem Clients und Server mit fast allen Nachrichtenbrokern kommunizieren können. Es ist eine Alternative zu AMQP (Advanced Message Queuing Protocol) und JMS (Java Messaging Service).

STOMP definiert ein Protokoll für die Kommunikation zwischen Client und Server mithilfe der Messaging-Semantik. Die Semantik befindet sich über den WebSockets und definiert Frames, die WebSockets-Frames zugeordnet sind.

Die Verwendung von STOMP gibt uns die Flexibilität, Clients und Server in verschiedenen Programmiersprachen zu entwickeln. In diesem aktuellen Beispiel verwenden wir STOMP für Nachrichten zwischen Client und Server.

4. WebSocket Server

Weitere Informationen zum Erstellen von WebSocket-Servern finden Sie in diesem Artikel.

5. WebSocket Client

Um mit dem WebSocket-Server zu kommunizieren, muss der Client die WebSocket-Verbindung initiieren, indem er eine HTTP-Anforderung an einen Server mit einem ordnungsgemäß festgelegten Upgrade- Header sendet :

GET ws://websocket.example.com/ HTTP/1.1 Origin: //example.com Connection: Upgrade Host: websocket.example.com Upgrade: websocket

Bitte beachten Sie, dass die WebSocket-URLs ws- und wss- Schemata verwenden, die zweite bezeichnet sichere WebSockets.

Der Server antwortet, indem er den Upgrade- Header in der Antwort sendet, wenn die WebSockets-Unterstützung aktiviert ist.

HTTP/1.1 101 WebSocket Protocol Handshake Date: Wed, 16 Oct 2013 10:07:34 GMT Connection: Upgrade Upgrade: WebSocket

Sobald dieser Vorgang (auch als WebSocket-Handshake bezeichnet) abgeschlossen ist, wird die anfängliche HTTP-Verbindung durch eine WebSocket-Verbindung über derselben TCP / IP-Verbindung ersetzt, nach der beide Parteien Daten gemeinsam nutzen können.

Diese clientseitige Verbindung wird von der WebSocketStompClient- Instanz initiiert .

5.1. Der WebSocketStompClient

Wie in Abschnitt 3 beschrieben, müssen wir zuerst eine WebSocket-Verbindung herstellen. Dies erfolgt mithilfe der WebSocketClient- Klasse.

Der WebSocketClient kann konfiguriert werden mit:

  • StandardWebSocketClient wird von jeder JSR-356-Implementierung wie Tyrus bereitgestellt
  • JettyWebSocketClient wird von der nativen WebSocket-API von Jetty 9+ bereitgestellt
  • Jede Implementierung von Spring's WebSocketClient

Wir werden StandardWebSocketClient verwenden , eine Implementierung von WebSocketClient in unserem Beispiel:

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. 

Standardmäßig unterstützt WebSocketStompClient SimpleMessageConverter . Da es sich um JSON-Nachrichten handelt, setzen wir den Nachrichtenkonverter auf MappingJackson2MessageConverter , um die JSON-Nutzdaten in Objekte zu konvertieren.

Während der Verbindung zu einem Endpunkt übergeben wir eine Instanz von StompSessionHandler , die die Ereignisse wie afterConnected und handleFrame behandelt .

Wenn unser Server SockJs-Unterstützung bietet, können wir den Client so ändern, dass SockJsClient anstelle von StandardWebSocketClient verwendet wird.

5.2. Der StompSessionHandler

Wir können eine StompSession verwenden , um ein WebSocket-Thema zu abonnieren. Dies kann durch Erstellen einer Instanz von StompSessionHandlerAdapter erfolgen, die wiederum den StompSessionHandler implementiert .

Ein StompSessionHandler bietet Lebenszyklusereignisse für eine STOMP-Sitzung. Zu den Ereignissen gehören ein Rückruf beim Aufbau der Sitzung und Benachrichtigungen bei Fehlern.

Sobald der WebSocket-Client eine Verbindung zum Endpunkt herstellt, wird der StompSessionHandler benachrichtigt und die afterConnected () -Methode aufgerufen, bei der wir das Thema mit StompSession abonnieren:

@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()); }

Stellen Sie sicher, dass der WebSocket-Server ausgeführt wird und der Client ausgeführt wird. Die Meldung wird auf der Konsole angezeigt:

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. Fazit

In diesem kurzen Tutorial haben wir einen Spring-basierten WebSocket-Client implementiert.

Die vollständige Implementierung finden Sie auf GitHub.