WebSocket Implementation Guide Part 1

March 10, 2023

WebSocket Implementation Guide

Introduction

Today, we'll explore the often-discussed topic of WebSocket. In system design, it's often implicit to implement chat functionality. Let's define some terms and proceed:

Scenario: UserA wants to send a simple message to UserB.

Steps:

  1. UserA sends a message to the server (Our application can be Spring or any other).
  2. The server sends a response to UserB.

In this scenario, UserA initiates the process, but not UserB. UserB is on the receiving end, and thus, the server has to send a response back to UserB without UserB explicitly requesting it. This violates the traditional client-server architecture.

This is where WebSocket comes into play. It establishes a two-way street where the server can also send a response back to the user when deemed necessary (in our case, if there's any pending message for the user).

Let's delve into the basics and then implement this together.

WebSocket Working

  1. The user or client initiates the HTTP request with an upgrade header, asking the server if it supports WebSocket or not.
  2. The server responds positively if possible, and a handshake is established.

Note: The above steps are crucial.

How to Implement

Server-Side Implementation via a Simple Spring Boot Application

  1. Add the WebSocket dependency:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
    <version>3.2.3</version>
</dependency>

Now define WebSocketConfig to tell handler and path.

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        System.out.println("Started registeringWebSocket");
        registry.addHandler(new MyWebSocketHandler(), "/websocket") // : This line registers a new WebSocket handler with the provided registry.
                .setAllowedOrigins("*"); // Allow connections from any origin for testing purposes
    }
}

Now the handler when msg comes

package org.example.configs;

import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;


@Component
public class MyWebSocketHandler extends TextWebSocketHandler {

    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

    private WebSocketSession session;


    @Override
    public void afterConnectionEstablished(WebSocketSession session) {
        this.session = session;
        System.out.println("Session established + " + session.getId());
        startSendingMessages();
    }


    private void startSendingMessages() {
        if (this.session == null || !this.session.isOpen()) {
            System.out.println("Session is not open. Cannot send messages.");
            return;
        }

        scheduler.scheduleAtFixedRate(() -> sendMessage(), 0, 1000, java.util.concurrent.TimeUnit.MILLISECONDS);
    }

    private void sendMessage() {
        if (this.session == null || !this.session.isOpen()) {
            System.out.println("Session is not open. Cannot send messages.");
            return;
        }

        try {
            session.sendMessage(new TextMessage("Hello, client! " + LocalDateTime.now()));
            System.out.println("Message sent to client.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

Important function is afterConnectionEstablished -> you get the session (how to identify where to send msg to).

Overall, this code represents a WebSocket handler that establishes a connection with a client, schedules periodic messages to be sent to the client, and sends greeting messages along with the current timestamp.

, Now the client side Code.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebSocket Client</title>
</head>
<body>
    <h1>WebSocket Example</h1>

    <script>
        // Create a WebSocket connection to the server
        const socket = new WebSocket('ws://localhost:8080/websocket');

        // Event listener for WebSocket connection open
        socket.onopen = function(event) {
            console.log('WebSocket connection opened');
        };

        // Event listener for receiving messages from the server
        socket.onmessage = function(event) {
            const message = event.data;
            console.log('Received message:', message);
            // Handle the received message as needed
        };

        // Event listener for WebSocket connection close
        socket.onclose = function(event) {
            console.log('WebSocket connection closed');
        };

        // Event listener for WebSocket connection errors
        socket.onerror = function(error) {
            console.error('WebSocket error:', error);
        };
    </script>
</body>
</html>

Overall, this HTML and JavaScript code set up a WebSocket client that connects to a WebSocket server running locally on port 8080, logs messages to the console for different WebSocket events, and provides placeholders to handle received messages and errors.

In short. This is all it takes to establish simple websocket from client to server.

For Chat message lets discover that in the next blog with code.


Profile picture

Created and Maintained by Kanishk Verma

Works in Goldman Sachs and trying to share little knowledge I have.

@KanishkVerma97

Comments