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