====== 04 - Servidor HTTP - 2 ====== ===== Servidor HTTP multicliente con ficheros estáticos ===== 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`.\\ \\ ===== Funcionamiento ===== - El servidor escucha en el puerto **8080**.\\ \\ - Cada vez que un cliente se conecta, se crea un hilo independiente para manejar su solicitud.\\ \\ - Si el cliente solicita `/`, se envía el fichero `index.html`.\\ \\ - Si solicita otro recurso (por ejemplo `/about.html`), se busca en la carpeta `www`.\\ \\ - Si el archivo no existe, se devuelve un **404 Not Found**.\\ \\ ===== Estructura del proyecto ===== 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 ===== Código ===== 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", "

404 Not Found

"); } } 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, "

" + statusCode + " " + statusText + "

"); } }
package es.cesguiro.socket; public class Main { public static void main(String[] args) { HttpServerMulti server = new HttpServerMulti(); server.start(); } } ===== Archivos HTML ===== **index.html** Bienvenido

Hola desde el Servidor HTTP multicliente

Este es el archivo index.html servido desde src/main/resources/www.

Ir a la página About

**about.html** Acerca de

Página About

Este servidor es un ejemplo básico de manejo de múltiples conexiones y ficheros estáticos en Java.

Volver al inicio

===== Ejecución ===== - Arranca el servidor (`Main.java`).\\ \\ - Abre un navegador y accede a: * http://localhost:8080/ → index.html * http://localhost:8080/about.html → about.html\\ \\ * Prueba con varios navegadores o pestañas a la vez para comprobar que atiende múltiples clientes.