Lección 13: WebSockets | Curso JavaScript

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.

AJAX vs WebSockets

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).

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

Conectar WebSocket

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

Enviar mensaje con WebSocket

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.

Error con WebSocket

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.

Desconectar WebSocket

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.

Ejercicio 13-1

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.

Ejercicio 13-2

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.

Atribución/Reconocimiento-NoComercial-SinDerivados 4.0 Internacional

¿Me invitas a un café? ☕

Puedes hacerlo usando el terminal.

ssh customer@andros.dev -p 5555

Comentarios

{{ comments.length }} comentarios

Nuevo comentario

Nueva replica  {{ formatEllipsisAuthor(replyComment.author) }}

Acepto la política de Protección de Datos.

Escribe el primer comentario