32 - Construyendo un web server en Rust desde cero - parte 1 diseño y primera implementación

32 - Construyendo un web server en Rust desde cero - parte 1 diseño y primera implementación

¡Bienvenidos a Rustaceo.es! En esta serie de artículos, construiremos un servidor web desde cero en Rust, utilizando conceptos clave del lenguaje y aprovechando su seguridad y eficiencia. Por supuesto, todo con la temática Pokémon para hacerlo más divertido. 🚀


🎯 Objetivos del proyecto #

Antes de escribir una sola línea de código, definamos qué queremos lograr con nuestro servidor web:

  1. Servir contenido dinámico y estático: Permitirá responder con datos predefinidos o dinámicamente generados.
  2. Eficiencia y seguridad: Aprovecharemos el modelo de seguridad de Rust para evitar errores comunes.
  3. Escalabilidad: Empezaremos con un modelo simple y luego lo expandiremos con manejo de rutas y concurrencia.

🛠 Retos a superar #

Construir un servidor web desde cero implica enfrentar varios desafíos:

  1. Manejo de conexiones: Cómo recibir y procesar solicitudes HTTP desde un cliente.
  2. Formato de respuesta: Construir respuestas válidas en formato HTTP.
  3. Paralelismo y concurrencia: Hacer que nuestro servidor pueda manejar múltiples peticiones simultáneamente.

Pero no nos preocupemos aún por todo esto. En esta primera parte, solo vamos a centrarnos en levantar un servidor básico que pueda recibir conexiones.


🏗 Primera implementación: servidor básico #

Empecemos creando la estructura básica de nuestro servidor. Para ello, utilizaremos std::net para manejar sockets y aceptar conexiones entrantes.

use std::net::{TcpListener, TcpStream};
use std::io::{Read, Write};

fn manejar_conexion(mut stream: TcpStream) {
    let mut buffer = [0; 512];
    stream.read(&mut buffer).unwrap();
    
    let respuesta = "HTTP/1.1 200 OK\r\n\r\n¡Bienvenido al Servidor Pokémon!";
    stream.write(respuesta.as_bytes()).unwrap();
    stream.flush().unwrap();
}

fn main() {
    let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
    println!("Servidor Pokémon escuchando en http://127.0.0.1:7878");
    
    for stream in listener.incoming() {
        let stream = stream.unwrap();
        manejar_conexion(stream);
    }
}

🔍 Explicación del código #

  • TcpListener::bind("127.0.0.1:7878"): Creamos un servidor que escucha en el puerto 7878.
  • listener.incoming(): Iteramos sobre las conexiones entrantes.
  • manejar_conexion(stream): Procesamos la conexión, leyendo la solicitud y respondiendo con un mensaje estático.

🚀 ¿Qué sigue? #

En esta primera versión, el servidor acepta peticiones y responde con un mensaje fijo. En la próxima parte, agregaremos manejo de rutas y procesamiento de peticiones, para que pueda responder dinámicamente según lo que el cliente solicite.

¡Hasta la próxima, Rustaceos!