DEV Community

Cover image for Breaching Boundaries with WebSockets: A Simple Dive into Real-Time Communication in JavaScript
EneasLari
EneasLari

Posted on • Originally published at eneaslari.com

Breaching Boundaries with WebSockets: A Simple Dive into Real-Time Communication in JavaScript

In the digital realm, timely and seamless communication is pivotal for an enhanced user experience. One technology that stands out in facilitating real-time communication is WebSockets. Unlike traditional HTTP, where communication is initiated only by the client, WebSockets offer a two-way communication channel between the client and server, making real-time updates a breeze.

Let’s embark on a simple journey to understand WebSockets and how they are implemented in JavaScript, along with practical examples. Additionally, we'll discern scenarios where they prove to be a better choice.

Understanding WebSockets

WebSockets provide a unique channel of communication where both the client and server can send data independently at any time. This is a significant upgrade from the conventional request-response model where the communication is always initiated by the client.

Implementing WebSockets in JavaScript

Let’s create a simple WebSocket connection in JavaScript. Firstly, ensure your server supports WebSocket connections.

// Creating a new WebSocket instance
const socket = new WebSocket('ws://your-websocket-server.com');

// Connection opened
socket.addEventListener('open', (event) => {
    socket.send('Hello Server!');
});

// Listen for messages
socket.addEventListener('message', (event) => {
    console.log('Message from server:', event.data);
});

// Connection closed
socket.addEventListener('close', (event) => {
    console.log('Server connection closed:', event.data);
});
Enter fullscreen mode Exit fullscreen mode

In this snippet:

  1. We create a new WebSocket instance, passing the WebSocket server URL.
  2. We attach an event listener for the open event, which triggers when the connection is established, sending a greeting to the server.
  3. We listen for any messages from the server with the message event.
  4. Finally, we have a listener for the close event, which triggers when the connection is closed.

When to Use WebSockets?

WebSockets are particularly useful when you have a need for real-time updates. Here are some use cases:

  1. Chat Applications: Real-time message delivery is crucial for chat applications, making WebSockets a perfect fit.
  2. Live Updates: Whether it's a stock market application or a live score update of a game, WebSockets provide the real-time data transmission required.
  3. Online Gaming: Multiplayer online games benefit from the low latency and real-time updates provided by WebSockets.
  4. Collaboration Tools: Tools like document editors or project boards, where multiple users collaborate in real-time, also benefit significantly from WebSockets.

WebSockets bridge the gap between client and server, making real-time communication not just a possibility, but a robust, efficient reality. As you delve into projects that require a seamless flow of data, harnessing the power of WebSockets in JavaScript will undoubtedly prove to be a game-changer.

Websocket server with NodeJs and express

Creating a WebSocket server alongside an Express application requires the ws library, which is a popular WebSocket library for Node.js. Below is a basic example of how you can set up a WebSocket server using Node.js and Express.

  1. Firstly, you'll need to install express and ws using npm:
npm install express ws
Enter fullscreen mode Exit fullscreen mode
  1. Now create a file named server.js and paste the following code into it:
const express = require('express');
const http = require('http');
const WebSocket = require('ws');

const app = express();

// Initialize a simple http server
const server = http.createServer(app);

// Initialize the WebSocket server instance
const wss = new WebSocket.Server({ server });

wss.on('connection', (ws) => {
    // Connection is up, let's add a simple event
    ws.on('message', (message) => {
        console.log('Received:', message);

        // Broadcast the message to all connected clients
        wss.clients.forEach(client => {
            if (client !== ws && client.readyState === WebSocket.OPEN) {
                client.send(`Broadcast: ${message}`);
            }
        });
    });

    // Send a welcome message to the new connection
    ws.send('Welcome to the WebSocket server!');
});

// Start the server on port 8080
server.listen(8080, () => {
    console.log('Server is listening on port 8080');
});
Enter fullscreen mode Exit fullscreen mode

In this code:

  • We create an Express app and an HTTP server.
  • We initialize a new WebSocket server instance, binding it to the HTTP server.
  • We listen for new WebSocket connections on the connection event. For each new connection, we:
    • Set up a listener for message events, logging the received message to the console and broadcasting it to all other connected clients.
    • Send a welcome message to the newly connected client.

Now, to start your server, run the following command in the terminal:

node server.js
Enter fullscreen mode Exit fullscreen mode

Your WebSocket server will now be running on http://localhost:8080. You can connect to it using the WebSocket client code from the previous section of the article, just replace 'ws://your-websocket-server.com' with 'ws://localhost:8080'.

Certainly! You can create a WebSocket server using just the ws library and Node.js's built-in http module. Below is how you could go about this:

  1. As before, ensure you have the ws library installed via npm:
npm install ws
Enter fullscreen mode Exit fullscreen mode
  1. Create a file named server.js and paste the following code into it:
const http = require('http');
const WebSocket = require('ws');

// Create an HTTP server
const server = http.createServer((req, res) => {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
});

// Initialize the WebSocket server instance
const wss = new WebSocket.Server({ server });

wss.on('connection', (ws) => {
    // Connection is established
    ws.on('message', (message) => {
        // Log the received message
        console.log('Received:', message);

        // Broadcast the message to all connected clients
        wss.clients.forEach(client => {
            if (client !== ws && client.readyState === WebSocket.OPEN) {
                client.send(`Broadcast: ${message}`);
            }
        });
    });

    // Send a welcome message to the new connection
    ws.send('Welcome to the WebSocket server!');
});

// Start the server on port 8080
server.listen(8080, () => {
    console.log('Server is listening on port 8080');
});
Enter fullscreen mode Exit fullscreen mode

In this code:

  • We create an HTTP server using Node.js's built-in http module.
  • We initialize a new WebSocket server instance, binding it to the HTTP server.
  • We listen for new WebSocket connections on the connection event. For each new connection, we:
    • Set up a listener for message events, logging the received message to the console and broadcasting it to all other connected clients.
    • Send a welcome message to the newly connected client.

To start your server, run the following command in the terminal:

node server.js
Enter fullscreen mode Exit fullscreen mode

Your WebSocket server will now be running on http://localhost:8080. You can connect to it using the WebSocket client code from your earlier request, just replace 'ws://your-websocket-server.com' with 'ws://localhost:8080'.

Creating Chat Room

First let's create a client's UI (a html page)

index.html

<!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>
    <button id="sendmessagebutton">Broadcast Message</button>
    <button id="sendtoserver">Send Message to server</button>
    <p id="logging">Logging:</p>
    <script src="client.js"></script>
  </body>
</html>

Enter fullscreen mode Exit fullscreen mode
  • The "Broadcast Message" button is for sending a message for broadcasting
  • The "Send message to server" is for sending message only to server
  • The paragraph is for logging things on the client

Now let's change a little bit the client.js

// Creating a new WebSocket instance
const socket = new WebSocket('ws://localhost:8080');

// Connection opened
socket.addEventListener('open', (event) => {
    var sayhi = {
        "type": "SENDTOSERVER",
        "payload": {
            "message": "Hello server, How are you?"
        }
    }
    socket.send(JSON.stringify(sayhi));
    document.getElementById("logging").innerText += "\n" + "You sent this mesage to the server: " + sayhi.payload.message

    document.getElementById("sendmessagebutton").addEventListener("click", () => {
        var newmessage = {
            "type": "BROADCAST",
            "payload": {
                "author": "A USER",
                "message": "Hi everyone!"
            }
        }
        socket.send(JSON.stringify(newmessage))
        document.getElementById("logging").innerText += "\n" + "You sent this mesage for broadcasting to the server: " + newmessage.payload.message
    })
    document.getElementById("sendtoserver").addEventListener("click", () => {
        var newmessage = {
            "type": "SENDTOSERVER",
            "payload": {
                "author": "A USER",
                "message": "This message is for server only"
            }
        }
        socket.send(JSON.stringify(newmessage))
    })
});

// Listen for messages
socket.addEventListener('message', (event) => {
    try {
        var message = JSON.parse(event.data);
        if (message.type === 'BROADCAST') {
            document.getElementById("logging").innerText += "\n" + "A client broadcasted: " + message.payload.message
        } else {
            document.getElementById("logging").innerText += "\n" + "You received this message: " + message.payload.message
        }

    } catch (e) {
        console.log('Wrong format');
        return;
    }
});

// Connection closed
socket.addEventListener('close', (event) => {
    console.log('Server connection closed:', event.data);
});
Enter fullscreen mode Exit fullscreen mode

We will change the server so it can differentiate the messages that are for broadcasting and for server only.

const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const path = require('path');
const app = express();

app.set("public", path.join(__dirname, "/"));
app.use(express.static(app.get("public")));
// Initialize a simple http server
const server = http.createServer(app);

// Initialize the WebSocket server instance
const wss = new WebSocket.Server({ server });

wss.on('connection', (ws) => {
    // Connection is up, let's add a simple event
    ws.on('message', (data) => {
        console.log('Received:', data.toString());
        let message;
        try {
            message = JSON.parse(data);

        } catch (e) {
            console.log('Wrong format');
            return;
        }

        if (message.type === 'BROADCAST') {
            // Broadcast the message to all connected clients
            wss.clients.forEach(client => {
                if (client !== ws && client.readyState === WebSocket.OPEN) {
                    var newmessage = {
                        "type": "BROADCAST",
                        "payload": {
                            "author": "Server",
                            "message": message.payload.message
                        }
                    }
                    client.send(JSON.stringify(newmessage));
                }
            });
        }
        if (message.type === 'SENDTOSERVER') {
            var respond = {
                "type": "SERVER_MESSAGE",
                "payload": {
                    "author": "Server",
                    "message": "I received your message:<<" + message.payload.message + ">>"
                }
            }
            ws.send(JSON.stringify(respond));
        }
    });

    // Send a welcome message to the new connection
    var message = { type: "SERVER_MESSAGE", payload: { message: "Hello client You just connected!" } }
    ws.send(JSON.stringify(message));

});

// sendFile will go here
app.get('/', function (req, res) {
    res.sendFile(path.join(__dirname, '/index.html'));
});

// Start the server on port 8080
server.listen(8080, () => {
    console.log('Server is listening on port 8080');
});
Enter fullscreen mode Exit fullscreen mode

Let's test things:

run node server.js

Then visit http://localhost:8080/

You should see this:

websocket

If you open a second tab you will connect a second client:

websocket

Then you can broadcast messages(press "Broadcast Message")
The server will receive the message and will broadcast it to the clients (except sender)

websocket

Also, you can send messages only to the server and get a response

websocket

That's for now!

You can find the code of this article here : GitHub Repository

Thank you for your time and for reading!

Top comments (0)