Lección 13: WebSockets
A diferencia de Fetch data o AJAX, el API de WebSocket es una tecnología avanzada que nos permite la comunicación bidireccional entre un cliente y un servidor. El servidor puede enviar mensajes al cliente y el cliente al servidor por el mismo camino.
Esta tecnología es indispensable para hacer tareas como:
- Aplicaciones en tiempo real, como un Chat o una red social.
- Envío de mensajes a un cliente específico, como unas notificaciones.
- Envío de mensajes masivos, como un videojuego multijugador.
- Aplicaciones de colaboración, como Google Drive o Notion.
Servidor
Para ilustrar las funcionalidades de WebSocket sin recurrir a servicios complejos o de pago, crearemos un pequeño servidor. Esta lección no aspira a enseñar backend con JavaScript o ahondar en Node
, sino ofrecer una elemental herramienta para aprender WebSockets.
Crearemos un servidor que devolverá cualquier información enviada a todos clientes conectados (Broadcast
).
Primero nos aseguramos que disponemos de Node.js
(binario para la ejecución de JavaScript) y npm
(gestor de paquetes JavaScript) instalado en el equipo.
node --version
npm --version
En ambos casos nos enseñará la versión instalada. En caso contraría mostrará un error que deberemos arreglar antes de continuar.
Ahora instalaremos las bibliotecas de WebSockets
.
Nos situamos sobre una carpeta nueva, para no mezclar con otros trabajos, y ejecutaremos.
npm install ws
Creamos un archivo llamado index.js
, donde nos encontramos situados, y pega el siguiente código.
// Importaciones
const WebSocket = require("ws");
const http = require("http");
// Creamos una instacia del servidor HTTP (Web)
const server = http.createServer();
// Creamos y levantamos un servidor de WebSockets a partir del servidor HTTP
const wss = new WebSocket.Server({ server });
// Escuchamos los eventos de conexión
wss.on("connection", function connection(ws) {
// Escuchamos los mensajes entrantes
ws.on("message", function incoming(data) {
// Iteramos todos los clientes que se encuentren conectados
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
// Enviamos la información recibida
client.send(data.toString());
}
});
});
});
// Levantamos servidor HTTP
server.listen(8080);
console.log("Servidor funcionando. Utiliza ws://localhost:8080 para conectar.")
Guardamos.
Ahora levantaremos el servidor
node index.js
¡Listo! Para conectarnos con el cliente usaremos ws://localhost:8080
. Lo dejamos funcionando y pasamos a crear un cliente.
Cliente
Conectar
Nativamente disponemos de un API para realizar las interacciones. Necesitaremos usar el objeto WebSocket
y guardarlo en una variable para utilizar sus eventos o funcionalidades.
const miWebSocket = new WebSocket(url [, protocolos]);
Puede ser utilizado incluyendo el protocolo junto a la ruta completa .
const miWebSocket = new WebSocket("ws://miservidor.com");
O separando los protocolos a utilizar como segundo argumento.
const miWebSocket = new WebSocket("miservidor.com", ["ws", "wss"]);
Al igual que existe una diferencia entre http
y https
, siendo el último seguro, en el protocolo de WebSockets también nos la encontraremos.
- ws: WebSockets.
- wss: WebSockets seguro.
const miWebSocket = new WebSocket("ws://miservidor.com");
Siendo más seguro.
const miWebSocket = new WebSocket("wss://miservidor.com");
Además dispondremos de un evento que será lanzado al conectar.
const miWebSocket = new WebSocket("wss://miservidor.com");
function open () {
// Abre conexión
console.log("WebSocket abierto.");
}
miWebSocket.addEventListener("open", open);
Mensajes
Escuchar
Si queremos recoger los mensajes enviados por el servidor, u otros clientes, debemos estar atentos al evento message
.
const miWebSocket = new WebSocket("wss://miservidor.com");
function message (evento) {
// Se recibe un mensaje
console.log("WebSocket ha recibido un mensaje");
// Mostrar mensaje en HTML
misRespuestas.innerHTML = misRespuestas.innerHTML.concat(evento.data, "<br>");
}
miWebSocket.addEventListener("message", message);
Emitir
Para enviar mensajes al servidor disponemos de la función send()
.
const miWebSocket = new WebSocket("wss://miservidor.com");
miWebSocket.send("Mi mensaje");
Gestión de errores
No siempre irá todo como esperamos, puede existir cortes de conexión por caídas de la red o problemas en el servidor.
Par ello estaremos alerta del evento error
.
const miWebSocket = new WebSocket("wss://miservidor.com");
function error (evento) {
// Ha ocurrido un error
console.error("WebSocket ha observado un error: ", evento);
}
miWebSocket.addEventListener("error", error);
Desconectar
Para la situación en que se desconecte el cliente o se rompa la conexión, posiblemente por un fallo importante, capturaremos el evento close
.
const miWebSocket = new WebSocket("wss://miservidor.com");
function close () {
// Cierra la conexión
console.log("WebSocket cerrado.");
}
miWebSocket.addEventListener("close", close);
Ejemplo
Con todo lo aprendido conectaremos con el servidor para enviar o recibir mensajes.
Crea un archivo llamado cliente-ws.html
con el siguiente contenido.
<!doctype html>
<html lang="es">
<head>
<meta charset="UTF-8"/>
<title>Ejemplo cliente de WebSocket</title>
</head>
<body>
<!-- Nuevo Mensaje -->
<input type="text" id="nuevo-mensaje">
<!-- Mensajes recibidos -->
<div id="respuestas"></div>
<script>
// Variables
const miWebSocket = new WebSocket("ws://localhost:8080");
const miNuevoMensaje = document.querySelector("#nuevo-mensaje");
const misRespuestas = document.querySelector("#respuestas");
// Funciones
function open () {
// Abre conexión
console.log("WebSocket abierto.");
}
async function message (evento) {
// Se recibe un mensaje
console.log("WebSocket ha recibido un mensaje");
// Mostrar mensaje en HTML
const mensajeRecibido = await evento.data.text(); // Arreglo para Node ya que devuelve Blob. Solo con "evento.data" debería ser suficiente
misRespuestas.innerHTML = misRespuestas.innerHTML.concat(mensajeRecibido, "<br>");
}
function error (evento) {
// Ha ocurrido un error
console.error("WebSocket ha observado un error: ", evento);
}
function close () {
// Cierra la conexión
console.log("WebSocket cerrado.");
}
function enviarNuevoMensaje (evento) {
// Evento tecla Enter
if(evento.code === "Enter") {
// Envia mensaje por WebSockets
miWebSocket.send(miNuevoMensaje.value);
// Borra texto en el input
miNuevoMensaje.value = "";
}
}
// Eventos de WebSocket
miWebSocket.addEventListener("open", open);
miWebSocket.addEventListener("message", message);
miWebSocket.addEventListener("error", error);
miWebSocket.addEventListener("close", close);
// Evento para envia nuevo mensaje
miNuevoMensaje.addEventListener("keypress", enviarNuevoMensaje);
</script>
</body>
</html>
Abre el archivo con diferentes ventanas al mismo tiempo para ver su funcionamiento.
Actividad 1
Crea un input
de texto para enviar notificaciones a todos los que estén conectados. Utiliza el servidor de ejemplo de la lección.
Nivel pesadilla 👹
Añade un sonido de alerta cuando recibas un nuevo mensaje.
Actividad 2
Construye un sencillo y liviano Chat. Utiliza el servidor de ejemplo de la lección.
Nivel pesadilla 👹
Lamentablemente cuando refrescamos la página se pierden los mensajes. Soluciona el problema almacenando cada mensaje en un Localstorage y obteniendo todos al entrar.
Actividad 3
Programa un juego de 3 en raya para jugar con un amigo en remoto. Utiliza el servidor de ejemplo de la lección.
Esta obra está bajo una Licencia Creative Commons Atribución-NoComercial-SinDerivadas 4.0 Internacional.
¿Me invitas a un café? ☕
Puedes hacerlo usando el terminal.
ssh customer@andros.dev -p 5555
Comentarios
Nuevo comentario
Nueva replica {{ formatEllipsisAuthor(replyComment.author) }}
Escribe el primer comentario
{{ comments.length }} comentarios