Computer scienceBackendNode.jsClient-server interaction

Websocket server

7 minutes read

In this topic, you will embark on a journey to understand and implement a WebSocket server using Node.js. WebSockets enable a persistent connection between a client and server, allowing for full-duplex communication. This means that data can be sent in both directions simultaneously. This technology is essential for applications that require real-time data exchange, including chat applications, live notifications, and online gaming. Let's dive into the mechanics of WebSockets and explore how you can leverage them in Node.js to create interactive and dynamic user experiences.

Websocket in node.js

Before we delve into setting up a WebSocket server, it's essential to understand what WebSockets are and how they operate within the Node.js environment. In contrast to the conventional request-response model utilized in HTTP, WebSockets enable a two-way interactive communication session. Once a WebSocket connection is established, both the client and server can exchange messages at any time until the connection is terminated.

Node.js, known for its event-driven and non-blocking I/O model, is an ideal environment for WebSockets. It efficiently manages multiple WebSocket connections, making it a robust choice for real-time applications.

Setting up websocket server

In Node.js, there are several tools available for setting up a WebSocket server, including socket.io and ws. The ws library is a simple and efficient library for creating WebSocket servers and clients in Node.js.

To set up a WebSocket server in Node.js with ws, follow these steps:

  • Install ws using npm in a new project.
  • Import it into a JavaScript file.
  • Create a new instance of a WebSocket server by invoking the WebSocketServer class, specifying the port for it to listen on.

Here's a basic example:

import { WebSocketServer } from 'ws';
const wss = new WebSocketServer({ port: 8080 });

Once your server is set up, you can define event handlers for various WebSocket events. The most important event to handle is connection, which is triggered when a client successfully connects to the server.

Within the connection event handler, you can also listen for errors, listen for messages from the client, and send messages to the client.

// Event listener for new connections to the server
wss.on('connection', function connection(ws) {
  console.log('A new client connected!');

  // Event listener for errors in the connection
  ws.on('error', console.error);

  // Event listener for messages from clients
  ws.on('message', function message(data) {
    console.log('received: %s', data);
  });

  // Send a welcome message to the client
  ws.send('Welcome to the websocket server');

});

The client or server can initiate the closing of the WebSocket connection. You can listen for this event using the close event.

ws.on('close', function close() { 
   console.log('The client has disconnected.'); 
}); 

By following these steps, you have set up a WebSocket server that can accept connections, receive messages, and send messages back to the clients.

The complete code looks like this:

import { WebSocketServer } from 'ws';

// Create a WebSocket server by specifying the port number
const wss = new WebSocketServer({ port: 8080 });

// Event listener for new connections to the server
wss.on('connection', function connection(ws) {
  console.log('A new client connected!');

  // Event listener for errors in the connection
  ws.on('error', console.error);

  // Event listener for messages from clients
  ws.on('message', function message(data) {
    console.log('received: %s', data);
  });

  // Send a welcome message to the client
  ws.send('Welcome to the websocket server');

  // Event listener for the connection closing  
  ws.on('close', function close() {
    console.log('Client disconnected');
  });

});

Run the server locally from the command line. The server will be running on ws://localhost:8080

node index.js

Socket.IO is a JavaScript library that enables real-time, bidirectional, and event-based communication between web clients and servers. To use Socket.IO, you install the socket.io package and set up your server as follows:

const server = require('http').createServer();
const io = require('socket.io')(server);

io.on('connection', (socket) => {
  console.log('a client connected');

  socket.on('message', (msg) => {
    console.log('message: ' + msg);
    io.emit('message', data); // Emit the message to all connected clients
  });

  socket.on('disconnect', () => {
    console.log('client disconnected');
  });
});

server.listen(8080, () => {
  console.log('listening on *:8080');
});

You can test the WebSocket server with a tool like Postman, and it would look something like this:

Server testing using postman
Server testing using Postman

Handling text and binary messages

Text messages can be sent and received by both the client and the server, and are typically used for general communication. Binary messages allow the transmission of binary data, such as images or files. They are received as instances of Buffer in Node.js. To handle binary messages, you should check if the message is an instance of Buffer; for text messages, you should verify if the message is a string.

ws.on('message', function message(data) {
    if (data instanceof Buffer) {
      console.log('Received binary message of %d bytes', data.length);

      // Echo the binary message back to the client
      ws.send(data);
    } else if (typeof data === 'string') {
      console.log('Received text message: %s', data);

      // Echo the text message back to the client
      ws.send(`You sent -> ${data}`);
    }
  });

Broadcasting messages to all connected clients

WebSocket broadcasting refers to the process of sending a message from the server to all connected clients simultaneously. This feature is particularly useful in scenarios where real-time updates or notifications need to be delivered to multiple clients at once.

Here is an example of a client WebSocket broadcasting to all connected clients, including itself:


ws.on('message', function message(data, isBinary) {
    wss.clients.forEach(function each(client) {
      if (client.readyState === WebSocket.OPEN) {
        client.send(data, { binary: isBinary });
      }
    });
  });

Inside the message event listener, the server iterates over all connected clients and checks if the client's connection is open. If the client's connection is open, it sends the data received from the original client to all connected clients.

Another instance involves a client WebSocket broadcasting to every other connected client, excluding itself:

ws.on('message', function message(data, isBinary) {
    wss.clients.forEach(function each(client) {
      if (client !== ws && client.readyState === WebSocket.OPEN) {
        client.send(data, { binary: isBinary });
      }
    });
  });

  

Within the message event listener, the server iterates over all connected clients and checks whether the current client is not the one who sent the original message and if the client's connection is open. If the client is not the one who sent the original message, it proceeds to send the message to every other connected client.

Conclusion

You now have the foundational knowledge of WebSockets in Node.js and the practical skills required to establish a WebSocket server. By harnessing the WebSocket protocol within the Node.js environment, you have unlocked the ability to create highly interactive and responsive applications. These applications can engage users with instantaneous data updates, enhancing the overall user experience.

As you progress, continue to experiment with the concepts you have learned. Additionally, it is crucial to consider the security implications of maintaining persistent connections. Always ensure that your WebSocket implementation is secure and robust against potential threats to safeguard your application and its users.

5 learners liked this piece of theory. 0 didn't like it. What about you?
Report a typo