04 - Servidor HTTP - 2

En el tema anterior vimos cómo crear un mini servidor HTTP muy básico.

Ahora vamos a mejorarlo para que:

  • Soporte múltiples clientes simultáneamente usando Threads.

  • Devuelva ficheros HTML estáticos desde la carpeta `src/main/resources/www`.

  1. El servidor escucha en el puerto 8080.

  2. Cada vez que un cliente se conecta, se crea un hilo independiente para manejar su solicitud.

  3. Si el cliente solicita `/`, se envía el fichero `index.html`.

  4. Si solicita otro recurso (por ejemplo `/about.html`), se busca en la carpeta `www`.

  5. Si el archivo no existe, se devuelve un 404 Not Found.

proyecto/
 ├─ src/main/java/es/cesguiro/socket/HttpServerMulti.java
 ├─ src/main/java/es/cesguiro/socket/ClientHandler.java
 ├─ src/main/java/es/cesguiro/socket/Main.java
 └─ src/main/resources/www/
      ├─ index.html
      └─ about.html

package es.cesguiro.socket;

import java.net.ServerSocket;
import java.net.Socket;

public class HttpServerMulti {

    private final int port = 8080;

    public void start() {
        System.out.println("Starting HTTP server on port " + port + "...");
        try {
            // Iniciar el servidor y aceptar múltiples conexiones
            ServerSocket serverSocket = new ServerSocket(port);
            System.out.println("HTTP server started. Waiting for requests...");

            while (true) {
                Socket clientSocket = serverSocket.accept();
                System.out.println("Client connected: " + clientSocket.getInetAddress());

                // Manejar la conexión en un nuevo hilo
                new Thread(new ClientHandler(clientSocket)).start();
            }
        } catch (Exception e) {
            System.err.println("Error starting HTTP server: " + e.getMessage());
            throw new RuntimeException("Failed to start HTTP server", e);
        }
    }
}

package es.cesguiro.socket;

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

public class ClientHandler implements Runnable {

    private final Socket clientSocket;

    public ClientHandler(Socket clientSocket) {
        this.clientSocket = clientSocket;
    }

    @Override
    public void run() {
        try (
                BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)
        ) {
            // Leer la primera línea de la solicitud HTTP
            String requestLine = in.readLine();
            System.out.println("Received request: " + requestLine);

            if (requestLine == null || !requestLine.startsWith("GET")) {
                sendError(out, 400, "Bad Request");
                return;
            }

            // Extraer recurso solicitado
            String[] parts = requestLine.split(" ");
            String resource = parts.length > 1 ? parts[1] : "/";
            if (resource.equals("/")) {
                resource = "/index.html";
            }

            // Buscar archivo en resources/www
            InputStream fileStream = getClass().getResourceAsStream("/www" + resource);
            if (fileStream != null) {
                String body = new String(fileStream.readAllBytes(), StandardCharsets.UTF_8);
                sendResponse(out, 200, "OK", body);
            } else {
                sendResponse(out, 404, "Not Found", "<h1>404 Not Found</h1>");
            }

        } catch (IOException e) {
            System.err.println("Error handling client connection: " + e.getMessage());
        } finally {
            try {
                clientSocket.close();
            } catch (Exception e) {
                System.err.println("Error closing client socket: " + e.getMessage());
            }
        }
    }

    private void sendResponse(PrintWriter out, int statusCode, String statusText, String body) {
        out.print("HTTP/1.0 " + statusCode + " " + statusText + "\r\n");
        out.print("Content-Type: text/html\r\n");
        out.print("Content-Length: " + body.getBytes(StandardCharsets.UTF_8).length + "\r\n");
        out.print("\r\n");
        out.print(body);
        out.flush();
    }

    private void sendError(PrintWriter out, int statusCode, String statusText) {
        sendResponse(out, statusCode, statusText, "<h1>" + statusCode + " " + statusText + "</h1>");
    }
}

package es.cesguiro.socket;

public class Main {
    public static void main(String[] args) {
        HttpServerMulti server = new HttpServerMulti();
        server.start();
    }
}

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Bienvenido</title>
</head>
<body>
    <h1>Hola desde el Servidor HTTP multicliente</h1>
    <p>Este es el archivo <strong>index.html</strong> servido desde <code>src/main/resources/www</code>.</p>
    <p><a href="/about.html">Ir a la página About</a></p>
</body>
</html>

about.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Acerca de</title>
</head>
<body>
    <h1>Página About</h1>
    <p>Este servidor es un ejemplo básico de manejo de múltiples conexiones y ficheros estáticos en Java.</p>
    <p><a href="/">Volver al inicio</a></p>
</body>
</html>

  1. Arranca el servidor (`Main.java`).

  2. Abre un navegador y accede a:
  • clase/daw/si/1eval/servidorhttp2.txt
  • Última modificación: 2025/08/13 17:46
  • por cesguiro