17  Ejercicios de la asignatura

17.1 Introducción a Redes

Investigación del Modelo TCP/IP

Investiga y compara el modelo de capas TCP/IP con tu propia experiencia navegando por Internet.

Tareas:

  1. Traza la ruta de una petición web:
    • Ejecuta el comando traceroute www.google.com (Linux/Mac) o tracert www.google.com (Windows)
    • Documenta cuántos saltos (hops) hay hasta llegar al destino
    • Identifica si alguno de los routers intermedios pertenece a tu ISP
  2. Análisis por capas: Para acceder a una página web (ej: https://www.google.com), describe qué ocurre en cada capa del modelo TCP/IP:
    • Capa de Aplicación: ¿Qué protocolo se utiliza?
    • Capa de Transporte: ¿TCP o UDP? ¿Por qué?
    • Capa de Red: ¿Qué información contienen los paquetes IP?
    • Capa de Acceso a la Red: ¿Qué tecnología física usas (WiFi, Ethernet, 4G)?
  3. Encapsulación:
    • Dibuja un diagrama mostrando cómo se encapsulan los datos en cada capa
    • Indica qué información añade cada capa (cabeceras)
  4. Reflexión:
    • ¿Por qué crees que el modelo está organizado en capas?
    • ¿Qué ventajas tiene esta separación?
    • Da un ejemplo de cómo puedes cambiar una capa sin afectar a las demás

17.2 Capa de Acceso

Análisis de Direcciones MAC y ARP

Investiga las direcciones MAC en tu red local y el protocolo ARP.

Tareas:

  1. Descubre tu dirección MAC:
    • En Linux/Mac: ip link show o ifconfig
    • En Windows: ipconfig /all
    • Anota la dirección MAC de tu interfaz de red principal
  2. Analiza la tabla ARP:
    • En Linux/Mac: arp -a o ip neigh show
    • En Windows: arp -a
    • Documenta:
      • ¿Cuántas entradas tiene tu tabla ARP?
      • ¿Reconoces alguna de las IPs? (router, otros dispositivos)
      • ¿Hay entradas incompletas o que fallan?
  3. Experimento con ARP:
    • Haz ping a tu router/gateway: ping 192.168.1.1
    • Vuelve a consultar la tabla ARP
    • ¿Qué ha cambiado?
  4. Investigación:
    • ¿Qué pasaría si dos dispositivos en la misma red tuvieran la misma dirección MAC?
    • ¿Por qué las direcciones MAC no se usan para enrutamiento en Internet?
    • ¿Cuál es la diferencia entre una dirección MAC y una dirección IP en términos de alcance?
  5. Analiza la estructura de la dirección MAC:
    • Tu MAC tiene formato: XX:XX:XX:YY:YY:YY
    • Los primeros 3 bytes (XX:XX:XX) son el OUI (Organizationally Unique Identifier)
    • Busca el fabricante de tu tarjeta de red en: https://maclookup.app/

17.3 Capa de Red

Análisis de Direccionamiento IP y Subredes

Dada la siguiente salida del comando ip addr en un sistema Linux, analiza la configuración de red y responde las preguntas:

$ ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP
    link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.100/24 brd 192.168.1.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fe12:3456/64 scope link
       valid_lft forever preferred_lft forever

3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP
    link/ether a4:5e:60:ab:cd:ef brd ff:ff:ff:ff:ff:ff
    inet 10.0.5.42/22 brd 10.0.7.255 scope global wlan0
       valid_lft forever preferred_lft forever

Preguntas:

  1. Direcciones de red: Para cada interfaz con IPv4, calcula:
    • La dirección de red
    • La dirección de broadcast
    • El rango de IPs válidas para hosts
    • El número total de hosts disponibles
  2. Clasificación:
    • ¿Qué interfaces tienen direcciones IP privadas? ¿Por qué?
    • ¿La dirección de loopback es pública o privada? ¿Para qué se utiliza?
  3. Máscara de subred:
    • Convierte las máscaras CIDR (/8, /24, /22) a formato decimal (ej: 255.255.255.0)
    • ¿Cuál es la diferencia entre /24 y /22 en términos de número de hosts?
  4. Escenario práctico:
    • Si quieres enviar un paquete desde esta máquina (192.168.1.100) a un servidor web en Internet (8.8.8.8), ¿qué interfaz se utilizaría?
    • ¿Necesitarías NAT? ¿Por qué?
  5. MTU:
    • ¿Qué significa MTU 1500?
    • Si envías un datagrama IP de 2000 bytes por eth0, ¿qué ocurrirá?

17.4 Capa de Transporte

Análisis de Conexiones TCP y UDP

Investiga las conexiones activas en tu sistema y analiza el comportamiento de TCP y UDP.

Tareas:

  1. Visualiza conexiones activas:

    • En Linux/Mac: netstat -tunap o ss -tunap
    • En Windows: netstat -ano
    • Identifica:
      • ¿Cuántas conexiones TCP tienes activas?
      • ¿Hay conexiones UDP? ¿A qué puertos?
      • ¿Reconoces algún servicio por su puerto? (80=HTTP, 443=HTTPS, 53=DNS, etc.)
  2. Analiza estados TCP:

    • Busca conexiones en estado ESTABLISHED, LISTEN, TIME_WAIT
    • ¿Qué significa cada estado?
    • ¿Por qué hay puertos en estado LISTEN?
  3. Compara TCP vs UDP: Completa la tabla:

    Característica TCP UDP
    Orientado a conexión ? ?
    Garantiza entrega ? ?
    Garantiza orden ? ?
    Control de flujo ? ?
    Overhead ? ?
    Velocidad ? ?
    Ejemplo de uso ? ?
  4. Investiga el handshake de TCP:

    • Dibuja el proceso de establecimiento de conexión (3-way handshake)
    • ¿Qué flags se utilizan? (SYN, ACK)
    • ¿Qué ocurre si se pierde uno de los paquetes?
  5. Caso práctico: Para un videojuego multijugador, ¿usarías TCP o UDP para los siguientes casos?

    • Chat de texto entre jugadores
    • Posición de los jugadores en tiempo real
    • Transferencia de archivos (mapas, texturas)
    • Sistema de login/autenticación

    Justifica cada respuesta.

17.5 Capa de Aplicación

Análisis de Petición HTTP

Investiga cómo funciona el protocolo HTTP usando herramientas de línea de comandos.

Tareas:

  1. Realiza una petición HTTP simple:

    curl -v http://example.com
    • Analiza la salida
    • Identifica las cabeceras de petición (Request headers)
    • Identifica las cabeceras de respuesta (Response headers)
    • ¿Qué código de estado se recibe?
  2. Compara HTTP vs HTTPS:

    curl -v http://google.com
    curl -v https://google.com
    • ¿Qué diferencias observas?
    • ¿Hay una redirección en la versión HTTP?
    • ¿Qué información adicional aparece en HTTPS?
  3. Investiga los métodos HTTP: Para cada método, describe:

    • GET
    • POST
    • PUT
    • DELETE
    • ¿Cuándo usarías cada uno en un videojuego?
  4. Analiza códigos de estado HTTP: Agrupa estos códigos por categoría (1xx, 2xx, 3xx, 4xx, 5xx):

    • 200, 201, 301, 302, 400, 401, 403, 404, 500, 502, 503
    • ¿Qué significa cada categoría?
    • Da un ejemplo de cuándo podrías recibir cada código en un juego
  5. Investiga DNS:

    nslookup google.com
    • ¿Qué IP(s) se resuelven?
    • ¿Por qué hay múltiples IPs?
    • ¿Qué pasaría si el DNS no funcionara?

17.6 JavaScript

Sistema de Inventario de Videojuego

Crea un sistema de inventario para un videojuego utilizando JavaScript moderno (ES2015+). El sistema debe:

  1. Crear una clase Inventario que pueda almacenar items con las siguientes propiedades:
    • nombre (string)
    • cantidad (number)
    • tipo (string): “arma”, “consumible”, o “quest”
  2. La clase Inventario debe tener los siguientes métodos:
    • agregarItem(nombre, cantidad, tipo): Añade un item al inventario. Si el item ya existe, incrementa su cantidad.
    • usarItem(nombre, cantidad): Reduce la cantidad del item especificado. Si llega a 0, elimina el item.
    • obtenerItemsPorTipo(tipo): Retorna un array con todos los items de un tipo específico.
    • get totalItems(): Getter que retorna el número total de items diferentes en el inventario.
  3. Implementa validaciones:
    • La cantidad nunca puede ser negativa
    • El tipo debe ser uno de los válidos (“arma”, “consumible”, “quest”)
    • No se puede usar más cantidad de la disponible
  4. Guarda el inventario en localStorage cada vez que se modifique y permite cargarlo cuando se crea una nueva instancia.

Requisitos técnicos:

  • Utiliza la sintaxis de clases ES2015+
  • Usa getters/setters cuando sea apropiado
  • Emplea métodos de arrays modernos (map, filter, etc.)
  • Implementa manejo de errores con try-catch
  • Usa template literals para mensajes

Ejemplo de uso:

const inventario = new Inventario();
inventario.agregarItem("Espada de Fuego", 1, "arma");
inventario.agregarItem("Poción de Salud", 5, "consumible");
inventario.agregarItem("Llave Antigua", 1, "quest");

console.log(`Total de items: ${inventario.totalItems}`); // 3

inventario.usarItem("Poción de Salud", 2);
const consumibles = inventario.obtenerItemsPorTipo("consumible");
console.log(consumibles); // [{ nombre: "Poción de Salud", cantidad: 3, tipo: "consumible" }]

17.7 Phaser

Sistema de Puntuación Persistente

Crea un sistema de puntuación para un juego Phaser que:

  1. Muestre la puntuación actual en pantalla durante el juego
  2. Guarde la puntuación más alta (high score) en localStorage
  3. Muestre el high score en la pantalla principal
  4. Permita resetear el high score

Requisitos:

  • Crea una escena de Phaser con:
    • Un texto que muestre “Score: X”
    • Un texto que muestre “High Score: Y”
    • Un botón o tecla para incrementar la puntuación (simular evento del juego)
    • Un botón para resetear el high score
  • Implementa la lógica para:
    • Incrementar la puntuación cuando ocurra un evento (ej: presionar SPACE)
    • Comparar la puntuación actual con el high score
    • Actualizar el high score si se supera
    • Persistir el high score en localStorage
    • Cargar el high score guardado al iniciar

Pista: Utiliza localStorage.setItem() y localStorage.getItem() para la persistencia.

Estructura sugerida:

class GameScene extends Phaser.Scene {
    constructor() {
        super('GameScene');
        this.score = 0;
        this.highScore = 0;
    }

    create() {
        // Cargar high score
        // Crear textos
        // Configurar controles
    }

    update() {
        // Actualizar puntuación
    }
}

17.8 REST - Introducción

Diseño de API REST para Videojuego

Diseña una API RESTful para un sistema de gestión de jugadores y partidas de un videojuego.

Requisitos:

  1. Define los recursos principales:
    • Jugadores (players)
    • Partidas (games)
    • Puntuaciones (scores)
  2. Diseña los endpoints siguiendo principios REST: Para cada operación, especifica:
    • Método HTTP (GET, POST, PUT, DELETE)
    • Ruta del endpoint
    • Código de estado esperado
    • Ejemplo de request/response
    Operaciones requeridas:
    • Listar todos los jugadores
    • Obtener un jugador específico
    • Crear un nuevo jugador
    • Actualizar información de un jugador
    • Eliminar un jugador
    • Obtener todas las partidas de un jugador
    • Crear una nueva partida
    • Obtener el top 10 de puntuaciones
  3. Aplica convenciones RESTful:
    • Usa nombres en plural para recursos
    • Usa IDs en la URL para recursos específicos
    • Usa query parameters para filtros y paginación
    • Diseña URLs jerárquicas para relaciones
  4. Diseña las estructuras de datos: Define el formato JSON para:
    • Un jugador (Player)
    • Una partida (Game)
    • Una puntuación (Score)

Ejemplo de formato:

GET /api/players/123
Respuesta: 200 OK
{
  "id": 123,
  "username": "player1",
  ...
}

17.9 REST - Cliente

Cliente REST con Fetch API

Implementa un cliente JavaScript que consuma la API REST de un videojuego usando Fetch API.

Requisitos:

  1. Crea funciones para consumir la API: Implementa las siguientes funciones usando fetch():

    async function getPlayers() { ... }
    async function getPlayer(id) { ... }
    async function createPlayer(playerData) { ... }
    async function updatePlayer(id, updates) { ... }
    async function deletePlayer(id) { ... }
    async function getTopScores(limit = 10) { ... }
  2. Manejo de errores:

    • Verifica el código de estado de la respuesta
    • Lanza excepciones personalizadas para errores HTTP
    • Maneja errores de red (ej: servidor no disponible)
  3. Implementa una clase GameAPI: Encapsula todas las funciones en una clase con:

    • Base URL configurable
    • Métodos para cada operación
    • Manejo centralizado de errores
    • Headers comunes (Content-Type, Authorization si aplica)
  4. Crea una interfaz de usuario simple:

    • Botón para obtener el top 10 de puntuaciones
    • Mostrar los resultados en una lista HTML
    • Indicador de carga durante la petición
    • Mensaje de error si falla

Estructura sugerida:

class GameAPI {
    constructor(baseURL) {
        this.baseURL = baseURL;
    }

    async request(endpoint, options = {}) {
        // Método helper para hacer peticiones
    }

    async getPlayers() { ... }
    async createPlayer(data) { ... }
    // ... más métodos
}

Uso esperado:

const api = new GameAPI('https://api.mygame.com');

// Obtener jugador
const player = await api.getPlayer(123);
console.log(player.username);

// Crear nuevo jugador
const newPlayer = await api.createPlayer({
    username: 'newbie',
    email: 'newbie@example.com'
});

17.10 REST - Servidor

Implementar un Servidor REST con Express

Crea un servidor REST básico para gestionar jugadores de un videojuego usando Node.js y Express.

Requisitos:

  1. Configura un proyecto Express:

    npm init -y
    npm install express
  2. Implementa los siguientes endpoints:

    • GET /api/players - Listar todos los jugadores
    • GET /api/players/:id - Obtener un jugador por ID
    • POST /api/players - Crear un nuevo jugador
    • PUT /api/players/:id - Actualizar un jugador
    • DELETE /api/players/:id - Eliminar un jugador
  3. Almacenamiento en memoria:

    • Usa un array para almacenar los jugadores temporalmente
    • Cada jugador debe tener: id, username, level, score
  4. Validaciones:

    • Verificar que username no esté vacío
    • Verificar que level y score sean números
    • Retornar error 400 si los datos son inválidos
    • Retornar error 404 si el jugador no existe
  5. Middleware:

    • Usa express.json() para parsear JSON
    • Añade un middleware de logging que imprima cada petición

Estructura sugerida:

const express = require('express');
const app = express();

// Datos en memoria
let players = [
    { id: 1, username: "player1", level: 5, score: 1000 },
    { id: 2, username: "player2", level: 3, score: 500 }
];
let nextId = 3;

// Middleware
app.use(express.json());

// TODO: Implementar endpoints

app.listen(3000, () => {
    console.log('Server running on http://localhost:3000');
});

Bonus:

  • Añade un endpoint GET /api/players?level=X para filtrar por nivel
  • Implementa paginación con limit y offset

17.11 WebSockets - Introducción

Comparación REST vs WebSockets

Analiza las diferencias entre REST y WebSockets y determina cuándo usar cada uno.

Tareas:

  1. Completa la tabla comparativa:

    Aspecto REST (HTTP) WebSockets
    Protocolo base ? ?
    Conexión ? ?
    Comunicación ? (cliente→servidor) ?
    Overhead ? ?
    Tiempo real ? ?
    Escalabilidad ? ?
    Complejidad ? ?
  2. Casos de uso - ¿REST o WebSocket? Para cada escenario de videojuego, indica si usarías REST, WebSocket o ambos, y justifica:

    1. Chat entre jugadores en tiempo real
    2. Cargar lista de mapas disponibles
    3. Sincronizar posición de jugadores en un shooter multijugador
    4. Subir una puntuación al leaderboard
    5. Notificaciones de amigos que se conectan
    6. Descargar un mapa de 50MB
    7. Partida de ajedrez online por turnos
    8. Sistema de login/autenticación
  3. Investigación:

    • ¿Qué es el “handshake” de WebSocket?
    • ¿Por qué WebSocket usa HTTP inicialmente?
    • ¿Pueden atravesar WebSockets un firewall/proxy más fácilmente que un socket TCP puro?
  4. Diseño arquitectónico: Para un juego multijugador tipo battle royale:

    • ¿Qué información enviarías por REST?
    • ¿Qué información enviarías por WebSocket?
    • Dibuja un diagrama simple de la arquitectura

17.12 WebSockets - Cliente

Cliente WebSocket para Chat de Juego

Implementa un cliente WebSocket simple para un sistema de chat en tiempo real de un videojuego.

Requisitos:

  1. Crea una clase GameChat:

    • Constructor que reciba la URL del servidor WebSocket
    • Método connect() para establecer conexión
    • Método sendMessage(message) para enviar mensajes
    • Método disconnect() para cerrar la conexión
    • Callbacks para eventos: onMessage, onConnect, onDisconnect, onError
  2. Manejo de estados de conexión:

    • Mostrar indicador cuando se está conectando
    • Mostrar indicador cuando está conectado
    • Mostrar error si falla la conexión
    • Intentar reconectar automáticamente si se pierde la conexión
  3. Interfaz de usuario HTML:

    • Input para el nombre de usuario
    • Botón para conectar
    • Área de mensajes (mostrar historial)
    • Input para escribir mensaje
    • Botón para enviar mensaje
    • Indicador de estado de conexión
  4. Formato de mensajes JSON:

    // Cliente → Servidor (enviar mensaje)
    {
      type: "message",
      username: "player1",
      text: "Hola a todos"
    }
    
    // Servidor → Cliente (mensaje broadcast)
    {
      type: "message",
      username: "player2",
      text: "Hola player1!",
      timestamp: "2025-11-06T10:30:00Z"
    }
    
    // Servidor → Cliente (usuario conectado)
    {
      type: "user_joined",
      username: "player3"
    }

Estructura sugerida:

class GameChat {
    constructor(serverURL) {
        this.serverURL = serverURL;
        this.ws = null;
        this.username = null;

        // Callbacks
        this.onMessage = null;
        this.onConnect = null;
        this.onDisconnect = null;
        this.onError = null;
    }

    connect(username) {
        // TODO: Establecer conexión WebSocket
    }

    sendMessage(text) {
        // TODO: Enviar mensaje al servidor
    }

    disconnect() {
        // TODO: Cerrar conexión
    }
}

Bonus:

  • Mostrar quién está escribiendo (“player2 is typing…”)
  • Soporte para comandos especiales (“/help”, “/users”)
  • Emoticones o formato básico de texto

17.13 WebSockets - Servidor

Servidor WebSocket para Chat de Juego

Implementa un servidor WebSocket simple usando Node.js y la librería ws.

Requisitos:

  1. Instala las dependencias:

    npm init -y
    npm install ws
  2. Implementa el servidor WebSocket:

    • Servidor escuchando en el puerto 8080
    • Manejar conexiones de múltiples clientes simultáneamente
    • Broadcast de mensajes a todos los clientes conectados
    • Gestionar usuarios (username por cliente)
  3. Tipos de mensajes:

    • register: Cliente envía su username al conectar
    • message: Cliente envía mensaje de chat
    • user_joined: Servidor notifica cuando alguien se une
    • user_left: Servidor notifica cuando alguien se va
  4. Funcionalidades:

    • Almacenar usuarios conectados con su websocket y username
    • Broadcast a todos excepto al emisor
    • Notificar a todos cuando un usuario se conecta/desconecta
    • Manejo de errores y desconexiones

Estructura sugerida:

const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });

// Almacenar clientes conectados
const clients = new Map(); // ws -> {username, ws}

wss.on('connection', (ws) => {
    console.log('New client connected');

    ws.on('message', (message) => {
        // TODO: Manejar mensajes
    });

    ws.on('close', () => {
        // TODO: Manejar desconexión
    });
});

Bonus:

  • Logging con timestamp de cada evento
  • Comando “/users” para listar usuarios conectados
  • Límite máximo de clientes simultáneos
  • Heartbeat/ping para detectar conexiones muertas