Usando WebSockets con ws

Ejemplo de uso de WebSockets


En el artículo anterior hicimos un ejemplo con Server-Sent Events. Ahora vamos a ver como hacerlo utilizando WebSockets y así poder enviar y recibir mensajes desde ambos extremos, tanto desde el cliente como desde el servidor.

Estructura principal del ejemplo

Lo primero es crear la estructura general del ejercicio. En este caso vamos a hacer dos servidores: server escuchando en el puerto 4321 y client escuchando en el puerto 8080. Observa que estamos creando un servidor de WebSockets con la librería ws, pasándole el servidor server que creamos como parámetro:

import { createServer } from "node:http";
import { readFile } from "node:fs/promises";
import { WebSocketServer } from "ws";

const SERVER_PORT = 4321;
const CLIENT_PORT = 8080;

// Server
const server = createServer();
const wss = new WebSocketServer({ server });
server.listen(SERVER_PORT, () => console.log(`Servidor en http://localhost:${SERVER_PORT}`));

// Client
const client = createServer( /* ... */ );
client.listen(CLIENT_PORT, () => console.log(`Cliente en http://localhost:${CLIENT_PORT}`));

Atento a wss, que es la instancia del servidor de Web Socket Server con la que vamos a estar trabajando a continuación.

El servidor

Vamos ahora a implementar el servidor. Observa que todo ocurre dentro del evento connection, que se produce cuando se realiza una conexión de un cliente con el servidor de WebSockets (lo veremos más adelante, en El cliente).

En ese fragmento de código, lo más importante es el objeto ws que tenemos como parámetro, que es el WebSocket en cuestión:

wss.on("connection", (ws) => {
  console.log("Client connected...");

  setInterval(() => {
    const data = {
      type: "message",
      message: `Hola desde el servidor!`,
      timestamp: new Date().toISOString(),
    };
    ws.send(JSON.stringify(data));
  }, 5000);

  ws.on("error", error => console.error("ERROR: ", error));
  ws.on("message", data => console.log("Received: ", JSON.parse(data)));
});

Una vez el cliente se conecte, ejecutamos un setInterval() que enviará mensajes al cliente cada 5 segundos utilizando ws.send(). Además, estará escuchando mensajes de error y mensajes recibidos desde el cliente, para mostrarlos por consola.

El cliente

Por otro lado, recuerda que en este ejemplo estamos abriendo un cliente y un servidor. El cliente está escuchando en el puerto 8080, por lo que si accedemos a http://localhost:8080´ nos abrirá el fichero index.html`, similar a como hicimos en el post Devolviendo una página estática.

Dicha página index.html tiene el siguiente contenido:

  • 1️⃣ Un HTML donde tenemos un <h1>, un <button> y un contenedor para los mensajes.
  • 2️⃣ Una etiqueta <style> donde tenemos los estilos CSS básicos de la página.
  • 3️⃣ Una etiqueta <script> donde tenemos la funcionalidad del cliente.
const ws = new WebSocket("ws://localhost:4321");
const container = document.querySelector(".container");
const button = document.querySelector("button");

const addMessage = (message) => {
  container.innerHTML += `<div>${message}</div>`;
}

ws.addEventListener("open", () => addMessage("Conectado"));
ws.addEventListener("message", ({ data }) => addMessage(`Recibido: ${data}`));
ws.addEventListener("close", () => addMessage("Desconectado"));
ws.addEventListener("error", () => addMessage("Error"));

button.addEventListener("click", () => {
  const data = {
    type: "message",
    message: "Hello from client!",
    timestamp: new Date().toISOString(),
  }
  ws.send(JSON.stringify(data));
});
<h1>Start</h1>
<button>Send message</button>
<div class="container"></div>

<style>
  body {
    background: indigo;
    color: white;
    font-size: 2rem;
  }
</style>

En la etiqueta <script> lo que hacemos es conectarnos al servidor WebSocket ws://localhost:4321 que iniciamos en el apartado anterior.

Observa que escuchamos los eventos open, message, close y error. Cuando se produzca uno de ellos, añadiremos un mensaje en la página. Además, cuando hagamos click en el botón de la página, enviaremos un mensaje al servidor utilizando ws.send().

Como puedes ver, un ejemplo sencillo que nos permite enviar mensajes desde el servidor al cliente y desde el cliente al servidor. Ten en cuenta que incluso podrían ser aplicaciones diferentes.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev