Implementa aplicaciones en tiempo real con WebSockets. Esta guía completa cubre desde conexiones básicas hasta arquitecturas escalables para chat, juegos multi-jugador y dashboards en tiempo real.
Diagrama de comunicación bidireccional con WebSockets
Contenido del Artículo
Fundamentos de WebSockets
Conexión persistente bidireccional cliente-servidor:
Bidireccional
Comunicación full-duplex
Baja latencia
Conexión persistente sin handshake repetido
Event-driven
Mensajes basados en eventos
// Conexión cliente
const socket = new WebSocket('wss://servidor-ejemplo.com');
// Eventos
socket.addEventListener('open', (event) => {
console.log('Conexión establecida');
socket.send('Hola servidor!');
});
socket.addEventListener('message', (event) => {
console.log('Mensaje recibido:', event.data);
});
socket.addEventListener('close', (event) => {
console.log('Conexión cerrada:', event.code, event.reason);
});
socket.addEventListener('error', (error) => {
console.error('Error en WebSocket:', error);
});
Implementación en Node.js
Crear servidor WebSocket con librerías populares:
// Usando ws (WebSocket puro)
const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 8080 });
server.on('connection', (socket) => {
console.log('Cliente conectado');
socket.on('message', (message) => {
console.log(`Mensaje recibido: ${message}`);
// Broadcast a todos los clientes
server.clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(`Usuario dice: ${message}`);
}
});
});
socket.on('close', () => {
console.log('Cliente desconectado');
});
});
// Usando Socket.IO (con fallback)
const io = require('socket.io')(3000);
io.on('connection', (socket) => {
console.log('Usuario conectado');
socket.on('chat message', (msg) => {
io.emit('chat message', msg); // Enviar a todos
});
socket.on('disconnect', () => {
console.log('Usuario desconectado');
});
});
Patrones Avanzados
Arquitecturas para aplicaciones escalables:
// Implementación de salas con Socket.IO
io.on('connection', (socket) => {
socket.on('unirse-sala', (sala) => {
socket.join(sala);
io.to(sala).emit('usuario-joined', socket.id);
});
socket.on('mensaje-sala', (sala, mensaje) => {
io.to(sala).emit('mensaje', { id: socket.id, mensaje });
});
socket.on('salir-sala', (sala) => {
socket.leave(sala);
io.to(sala).emit('usuario-left', socket.id);
});
});
Patrón | Implementación | Beneficio |
---|---|---|
Pub/Sub | Redis u otro broker de mensajes | Escalabilidad horizontal |
Salas/Canal | Grupos de conexiones | Broadcast selectivo |
Heartbeat | Ping/pong periódico | Detectar conexiones caídas |
Reconexión | Reintento exponencial | Resiliencia ante fallos |
Optimización y Seguridad
Mejores prácticas para producción:
WSS
Siempre usar WebSocket Secure
Autenticación
JWT o tokens durante handshake
Compresión
permessage-deflate
Balanceo
Sticky sessions para WebSockets
// Autenticación con JWT
const socket = io('https://servidor.com', {
auth: {
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
}
});
// Servidor (Socket.IO)
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (!token) {
return next(new Error('No autenticado'));
}
jwt.verify(token, 'SECRETO', (err, decoded) => {
if (err) return next(new Error('Token inválido'));
socket.user = decoded;
next();
});
});