WebSocket en JavaScript: aplicaciones avanzadas en tiempo real

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: más allá del WebSocket básico

La comprensión básica de WebSocket permite crear un chat simple o notificaciones. Sin embargo, para construir aplicaciones en tiempo real de nivel de producción — juegos multijugador, terminales financieros, sistemas de edición colaborativa — es necesario dominar técnicas avanzadas. En este artículo iremos más allá del "Hello, World" y analizaremos cómo crear aplicaciones WebSocket robustas, escalables y seguras en Node.js.

Abordaremos cuatro áreas clave: escalado con Redis, gestión de estados y salas, seguridad y autorización, y agrupación en clústeres para funcionar en múltiples procesadores. Todos los ejemplos de código están escritos en JavaScript utilizando la biblioteca ws y Node.js.



1. Escalado con Pub/Sub (Redis)

Una de las principales limitaciones de un servidor WebSocket es que no puede "comunicarse" con otras instancias. Si tienes dos servidores ejecutándose detrás de un balanceador de carga, un cliente conectado al servidor A no recibirá un mensaje enviado a través del servidor B. La solución es utilizar el patrón Pub/Sub (publicador-suscriptor) basado en Redis.

Redis actúa como un broker central: cada servidor se suscribe a un canal y publica mensajes en él. De esta manera, un mensaje enviado por cualquier servidor se distribuye instantáneamente a todos los demás.

const WebSocket = require('ws');const redis = require('redis');

const wss = new WebSocket.Server({ port: 8080 });const publisher = redis.createClient();const subscriber = redis.createClient();

// Nos suscribimos al canal 'broadcast'subscriber.subscribe('broadcast');subscriber.on('message', (channel, message) => { // Enviamos el mensaje a todos los clientes conectados wss.clients.forEach(client => { if (client.readyState === WebSocket.OPEN) { client.send(message); } });});

wss.on('connection', (ws) => { ws.on('message', (data) => { // Publicamos el mensaje en Redis publisher.publish('broadcast', data.toString()); });});

Este enfoque permite escalar horizontalmente tu aplicación casi infinitamente. Al agregar un nuevo servidor, simplemente crea su propia suscripción a Redis.



2. Gestión de salas y estados

En la mayoría de las aplicaciones en tiempo real es necesario agrupar a los clientes en "salas" (salas de chat, lobbies de juegos) y gestionar su estado. El wss.clients básico no proporciona esta funcionalidad. Implementemos un sistema de salas simple pero efectivo.

Crearemos un objeto rooms, donde la clave es el nombre de la sala y el valor es un Set de clientes WebSocket. Agregaremos métodos para entrar, salir y transmitir dentro de la sala.

const rooms = new Map();

function joinRoom(ws, roomName) { if (!rooms.has(roomName)) { rooms.set(roomName, new Set()); } rooms.get(roomName).add(ws); // Guardamos la sala en el objeto ws para acceso rápido ws.room = roomName;}

function leaveRoom(ws) { if (ws.room && rooms.has(ws.room)) { rooms.get(ws.room).delete(ws); if (rooms.get(ws.room).size === 0) { rooms.delete(ws.room); } delete ws.room; }}

function broadcastToRoom(roomName, message, exclude = null) { if (!rooms.has(roomName)) return; rooms.get(roomName).forEach(client => { if (client !== exclude && client.readyState === WebSocket.OPEN) { client.send(message); } });}

const wss = new WebSocket.Server({ port: 8080 });wss.on('connection', (ws) => { ws.on('message', (data) => { const msg = JSON.parse(data); switch (msg.type) { case 'join': joinRoom(ws, msg.room); break; case 'message': broadcastToRoom(ws.room, msg.text, ws); break; } }); ws.on('close', () => leaveRoom(ws));});

Para gestionar el estado (por ejemplo, posición del jugador, cursor) se pueden almacenar datos en un Map

Blogs

Book Recommendations