Software Development

WebSockets vs. SSE (Server-Sent Events): Exploring Real-Time Communication

Real-time communication between a client and a server is essential for creating dynamic and interactive web applications. Two popular technologies for achieving this are Server-Sent Events (SSE) and Web Sockets. Both allow for bi-directional communication, but they have different use cases and implementations. This article aims to explore the differences between SSE and WebSockets and provide some code examples using Java.

1. Server-Sent Events (SSE): One-Way Updates

Server-Sent Events (SSE) is a simple and efficient technology for pushing data from the server to the client over HTTP. Server-sent events establish a long-running HTTP connection, allowing the server to push data to the client. It’s ideal for scenarios where updates flow primarily from the server, like stock tickers, live news feeds or chat applications where only the server broadcasts messages.

1.1 What Makes SSE Attractive:

Here’s what makes SSE attractive:

  • Simplicity: Both server and client implementations are relatively straightforward.
  • Lightweight: One-way communication keeps the protocol efficient.
  • Broad Browser Support: Most modern browsers offer built-in support for SSE.

1.2 Limitations of SSE

Despite the appeal of SSE, it’s essential to contemplate these limitations before opting for it:

  • One-Way Communication: Data can only travel from server to client. Clients cannot directly send messages back.
  • Text-Based Data: SSE is limited to text data (UTF-8 format). It cannot transmit binary data like images or videos.

2. WebSockets: Two-Way Communication

WebSockets provide a full-duplex communication channel over a single, long-lived connection between the client and the server. Unlike SSE, WebSockets allow both the client and the server to send messages to each other at any time. This versatility makes them perfect for interactive applications like chat or collaborative editing.

2.1 Advantages of WebSockets

WebSockets offer several advantages:

  • Full-Duplex Communication: Data can flow seamlessly in both directions, fostering true interactivity.
  • Low Latency: The communication channel is persistent, minimizing delays in data exchange.
  • Rich Communication: WebSockets support not only text but also binary data formats, allowing for more versatile data transmission.

2.2 Considerations

While powerful, WebSockets come with some considerations:

  • Complexity: Implementing WebSockets involves a handshake process and handling two-way message flow, making it slightly more complex than SSE.
  • Handshake Overhead: Establishing a WebSocket connection requires an initial handshake, adding a small overhead compared to SSE.

3. Code Examples

To solidify our understanding, here are illustrative Java/Jakarta EE code snippets showcasing both SSE and WebSockets. This section explores Server-Sent Events (SSE) and WebSockets for real-time communication in web applications, focusing on Java/Jakarta EE with a RESTful approach using the javax.ws.rs package and javax.ws.rs.sse for SSE support.

3.1 Server-Sent Events (SSE)

SSE is a great choice for scenarios where updates primarily flow from the server to the client.

3.1.2 Server-side (SSE Resource):

This code defines a JAX-RS resource that acts as the SSE Server endpoint.

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.sse.Sse;
import jakarta.ws.rs.sse.SseEventSink;

@Path("/events")
public class SSEServer {

    @GET
    @Produces(MediaType.SERVER_SENT_EVENTS)
    public void getServerSentEvents(@jakarta.ws.rs.core.Context SseEventSink eventSink, @jakarta.ws.rs.core.Context  Sse sse) {
        // Set up a new thread to generate events
        new Thread(() -> {
            try {
                for (int i = 0; i < 20; i++) {
                    // Send events to the client
                    eventSink.send(sse.newEventBuilder().name("sseevent").data(" " + i).build());
                    Thread.sleep(2000); // Simulate delay
                }
            } catch (InterruptedException e) {
            } finally {
                // Close the event sink when done
                eventSink.close();
            }
        }).start();
    }
}

The above code demonstrates an SSE server that sends simulated data updates at regular intervals.

3.1.2 HTML5 for SSE Client

This HTML page demonstrates subscribing to the SSE endpoint and displaying received data:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>SSE Client</title>
    </head>
    <body>
        <h1>Server-Sent Events (SSE) Client</h1>

        <div style="background-color: #64a4bd; width: 200px; padding: 10px">

            <h4 id="eventId"></h4>

        </div>

        <script>
            // Function to handle incoming events
            function handleEvent(event) {
                var eventsDiv = document.getElementById("eventId");
                eventsDiv.innerHTML = 'Received event: ' + event.data + '<br>';
            }

            // Create a new EventSource pointing to the SSE endpoint
            var eventSource = new EventSource("rest/events");

            // Attach event listener to handle incoming events
            eventSource.addEventListener('sseevent', handleEvent);
            //eventSource.onmessage = handleEvent;

            // Event listener to handle SSE errors
            eventSource.onerror = function (event) {
                eventSource.close();
                console.error('SSE error:', event);

            };
        </script>

    </body>
</html>

This code creates an EventSource object, subscribing to the server’s SSE endpoint. The output is:

Fig 1: Output from SSE Example

3.2 WebSockets

WebSockets provide full-duplex communication, allowing both server and client to send and receive messages in real time.

3.2.1 Server-side (JAX-RS WebSocket Endpoint)

This code defines a JAX-RS annotated WebSocket endpoint for bi-directional communication.

import jakarta.websocket.OnClose;
import jakarta.websocket.OnError;
import jakarta.websocket.OnMessage;
import jakarta.websocket.OnOpen;
import jakarta.websocket.Session;
import jakarta.websocket.server.ServerEndpoint;
import java.io.IOException;

@ServerEndpoint("/websocket")
public class WebSocketServer {

    @OnOpen
    public void onOpen(Session session) {
        System.out.println("WebSocket opened: " + session.getId());
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("Message received: " + message);
        try {
            session.getBasicRemote().sendText("Echo: " + message); // Echo back the message
        } catch (IOException e) {
        }
    }

    @OnClose
    public void onClose(Session session) {
        System.out.println("WebSocket closed: " + session.getId());
    }

    @OnError
    public void onError(Throwable error) {
        System.out.println("" + error);
    }
}

3.2.2 HTML5 for WebSocket Client

This HTML page demonstrates connecting to the WebSocket endpoint and sending/receiving messages:

<!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 Client</h1>
        Messages<br/>
        <textarea id="messages" rows="6" cols="50" style="background-color: #E6E6FF; border-radius: 15px;margin-bottom: 10px;width: 40%;padding: 20px"></textarea><br/>
       
        <form id="messageForm" style="margin-bottom: 10px">
            <input type="text" id="messageInput" placeholder="Enter message" name="name">
            <input type="button" onclick="join()" value="Join"/>
            <input type="button" onclick="sendmessage()" value="Send"/><br/>
            <input type="button" onclick="disconnect()" value="Disconnect"/>
        </form><br/>
        <div id="output" style="margin-top: 10px; background-color: #E6E6FF; border-radius: 15px;width: 40%;padding: 20px"></div>
        <script language="javascript" type="text/javascript">
            // Create WebSocket connection
            const socket = new WebSocket('ws://localhost:8080/my-faces-app/websocket');

            var messageInput = document.getElementById('messageInput');
            var users = document.getElementById('users');
            var messages = document.getElementById('messages');

            var username;

            socket.onopen = function (evt) {
                onOpen(evt);
            };
            socket.onclose = function (evt) {
                onClose(evt);
            };
            socket.onerror = function (evt) {
                onError(evt);
            };
            socket.onmessage = function (evt) {
                onMessage(evt);
            };

            var output = document.getElementById('output');

            function join() {
                username = messageInput.value;
                socket.send(username + " joined");
                // Clear input field
                messageInput.value = '';
            }

            function sendmessage() {
                socket.send(username + ": " + messageInput.value);
                // Clear input field
                messageInput.value = '';
            }

            function onOpen() {
                writeToScreen("CONNECTED");
            }
            function onClose() {
                writeToScreen("DISCONNECTED");
            }

            function onMessage(evt) {
                writeToScreen("Message Received: " + evt.data);
                if (evt.data.indexOf("joined") !== -1) {
                    users.innerHTML += evt.data.substring(0, evt.data.indexOf(" joined")) + "\n";
                } else {
                    messages.innerHTML += evt.data + "\n";
                }
            }

            function onError(evt) {
                wrtieToScreen("Error : " + evt.data);
            }

            function disconnect() {
                socket.close();
            }

            function writeToScreen(message) {
                var pre = document.createElement("p");
                pre.style.wordWrap = "break-word";
                pre.innerHTML = message;

                output.appendChild(pre);
            }
        </script>
    </body>
</html>

Output is:

Fig 2: WebSocket Client output showing updated messages from two separate browsers
Fig 2: WebSocket Client output showing updated messages from two separate browsers

4. WebSockets vs. SSE: Comparative Analysis

Below is a tabular representation outlining the differences and similarities between WebSockets and Server-Sent Events (SSE):

FeatureWebSocketsServer-Sent Events (SSE)
Communication DirectionFull-duplex: Both client and server can send dataUnidirectional: The server pushes data to the client
ProtocolWebSocket protocolHTTP/HTTPS protocol
Browser SupportSupported by most modern browsersSupported by most modern browsers
Connection EstablishmentRequires handshakeUses standard HTTP connections
Continuous ConnectionMaintains a persistent connectionUses long-lived HTTP connections
Message TypesSupports binary and text messagesSupports only text messages
Server OverheadLowHigher due to HTTP headers and overhead
ScalabilityBetter scalability due to fewer connectionsMay be less scalable due to multiple connections
Error HandlingProvides built-in error-handling mechanismsLimited error-handling capabilities
UsageReal-time applications, gaming, and chat applicationsPush notifications, live updates, stock tickers, etc.
WebSockets vs. SSE

5. Conclusion

This article has explored using WebSockets vs. SSE. By understanding their strengths and weaknesses, we can make an informed decision for building real-time communication into our web applications. In conclusion, Server-Sent Events (SSE) and Web Sockets are powerful technologies for enabling real-time communication between clients and servers in web applications. SSE is simpler to implement and is ideal for scenarios where the server needs to push updates to the client. On the other hand, WebSockets offer full-duplex communication and are suitable for more interactive applications requiring bi-directional communication.

Omozegie Aziegbe

Omos holds a Master degree in Information Engineering with Network Management from the Robert Gordon University, Aberdeen. Omos is currently a freelance web/application developer who is currently focused on developing Java enterprise applications with the Jakarta EE framework.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button