sábado, 7 de marzo de 2026

10 Ejercicios Resueltos de Redes: Sockets TCP y UDP en Python y C (Nivel Universidad)

Cualquier aplicación moderna necesita conectarse a Internet. En la asignatura de Redes de Computadores, la teoría del Modelo OSI está muy bien, pero donde de verdad se aprende es programando Sockets.

En larebelion.com hemos preparado 10 ejercicios de exámenes de universidades españolas. Nos centraremos principalmente en la API de Sockets de Python por su claridad, pero incluiremos la base en C para los más puristas. Prepara tus puertos locales, ¡que empezamos a escuchar conexiones!


1. Servidor TCP Básico (UPM)

Enunciado: Crea un servidor TCP en Python que escuche en el puerto 8080. Cuando un cliente se conecte, debe enviarle el mensaje "Bienvenido al servidor" y cerrar la conexión.

import socket

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('0.0.0.0', 8080))
server.listen(5)
print("Servidor TCP escuchando en puerto 8080...")

while True:
    client_socket, addr = server.accept()
    print(f"Conexión establecida desde {addr}")
    client_socket.send(b"Bienvenido al servidor\n")
    client_socket.close()

2. Cliente TCP Básico (UPC)

Enunciado: Escribe el código del cliente en Python que se conecte al servidor TCP del ejercicio anterior (en localhost), reciba el mensaje, lo imprima por pantalla y se desconecte.

import socket

cliente = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cliente.connect(('127.0.0.1', 8080))

# Recibimos hasta 1024 bytes
respuesta = cliente.recv(1024)
print("Mensaje del servidor:", respuesta.decode('utf-8'))
cliente.close()

3. Servidor UDP de Eco (UV)

Enunciado: A diferencia de TCP, UDP no está orientado a conexión. Crea un servidor UDP en el puerto 9000 que reciba un mensaje y se lo devuelva al remitente exactamente igual (Echo Server).

import socket

# SOCK_DGRAM indica que usaremos UDP
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.bind(('0.0.0.0', 9000))
print("Servidor UDP Eco iniciado...")

while True:
    datos, direccion = server.recvfrom(1024)
    print(f"Recibido de {direccion}: {datos.decode()}")
    server.sendto(datos, direccion)

4. Cliente UDP interactivo (UGR)

Enunciado: Crea un cliente UDP que pida al usuario que escriba un texto por consola, lo envíe al servidor del ejercicio 3 y muestre la respuesta.

import socket

cliente = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
direccion_servidor = ('127.0.0.1', 9000)

mensaje = input("Escribe un mensaje para enviar: ")
cliente.sendto(mensaje.encode(), direccion_servidor)

respuesta, addr = cliente.recvfrom(1024)
print("Eco del servidor:", respuesta.decode())
cliente.close()

5. Estructuras en C: Inicializar un Socket (UC3M)

Enunciado: En C, las cosas son más manuales. Escribe el fragmento de código necesario en C para crear un socket TCP y preparar la estructura sockaddr_in para el puerto 80.

#include <sys/socket.h>
#include <netinet/in.h>

int server_fd;
struct sockaddr_in address;

// 1. Crear file descriptor del socket
server_fd = socket(AF_INET, SOCK_STREAM, 0);

// 2. Configurar la estructura de red
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(80); // htons convierte al formato de red

6. Python: Servidor TCP Multihilo (US)

Enunciado: Un servidor básico se bloquea con cada cliente. Usa la librería threading para crear un servidor TCP que asigne un hilo nuevo a cada cliente que se conecte, permitiendo conexiones concurrentes.

import socket
import threading

def manejar_cliente(conn, addr):
    print(f"Nuevo hilo para {addr}")
    conn.send(b"Hola desde un hilo concurrente!\n")
    conn.close()

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('0.0.0.0', 8888))
server.listen(5)

while True:
    conn, addr = server.accept()
    hilo = threading.Thread(target=manejar_cliente, args=(conn, addr))
    hilo.start()

7. Resolución de DNS (UAM)

Enunciado: Usa los métodos de socket en Python para preguntar al usuario un nombre de dominio (ej: google.com) y devolver su dirección IP (resolución DNS directa).

import socket

def obtener_ip():
    dominio = input("Introduce un dominio (ej. larebelion.com): ")
    try:
        ip = socket.gethostbyname(dominio)
        print(f"La IP de {dominio} es {ip}")
    except socket.gaierror:
        print("No se pudo resolver el hostname.")

obtener_ip()

8. Concurrencia en C usando Fork (UNED)

Enunciado: En C de Linux, la concurrencia a menudo se logra creando procesos hijos. Escribe la lógica del bucle principal de un servidor concurrente usando fork().

// Asumimos que socket, bind y listen ya están hechos
while(1) {
    int client_socket = accept(server_fd, NULL, NULL);
    if (fork() == 0) {
        // --- ESTE ES EL PROCESO HIJO ---
        close(server_fd); // El hijo no necesita escuchar
        send(client_socket, "Hola\n", 5, 0);
        close(client_socket);
        exit(0); // Matamos al hijo tras atender
    } else {
        // --- ESTE ES EL PROCESO PADRE ---
        close(client_socket); // El padre delega en el hijo
    }
}

9. Escáner de Puertos Básico (UMA)

Enunciado: Crea un script en Python que intente conectarse (usando connect_ex) a los puertos del 20 al 25 de la IP 127.0.0.1 e imprima cuáles están abiertos.

import socket

ip = '127.0.0.1'
print(f"Escaneando puertos en {ip}...")

for puerto in range(20, 26):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(0.5)
    # connect_ex devuelve 0 si la conexión es exitosa
    resultado = sock.connect_ex((ip, puerto))
    if resultado == 0:
        print(f"Puerto {puerto}: ABIERTO")
    sock.close()

10. Petición HTTP GET Manual (USAL)

Enunciado: HTTP no es magia, es solo texto enviado por un socket TCP. Escribe un cliente TCP que se conecte a un servidor web en el puerto 80, envíe la cabecera GET / HTTP/1.1 y reciba el HTML.

import socket

host = 'example.com'
cliente = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cliente.connect((host, 80))

# Petición HTTP cruda (los saltos de línea \r\n son obligatorios)
peticion = f"GET / HTTP/1.1\r\nHost: {host}\r\nConnection: close\r\n\r\n"
cliente.send(peticion.encode())

respuesta = cliente.recv(4096)
print(respuesta.decode())
cliente.close()

No hay comentarios:

Publicar un comentario