Long Polling vs WebSocket en Rust: la batalla por el tiempo real

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: ¿Por qué Rust es el candidato ideal para tiempo real?

\n\n

Imagina esta situación: estás escribiendo un servidor de chat, un terminal bursátil o un sistema de monitoreo en Rust. Los usuarios quieren recibir actualizaciones al instante. A nadie le gusta presionar el botón "Actualizar" manualmente — eso es cosa del pasado. Pero, ¿cómo organizar la entrega de datos del servidor al cliente?

\n\n

Durante mucho tiempo, la única forma fue el long polling — un truco elegante pero un poco "chapucero". Luego llegaron los WebSocket y revolucionaron el mundo del desarrollo web. Y ahora tenemos Rust — un lenguaje que permite exprimir al máximo ambos enfoques sin sacrificar la seguridad de la memoria.

\n\n

En este artículo no solo compararemos long polling y WebSocket en Rust — escribiremos ejemplos funcionales, los ejecutaremos y veremos qué sucede bajo el capó. Si estás desarrollando una aplicación en tiempo real en Rust y dudas sobre qué tecnología elegir — estás en el lugar correcto.

\n\n

Qué es Long Polling explicado de forma sencilla

\n\n

Long polling es una técnica en la que el cliente abre una solicitud HTTP al servidor y... espera. El servidor no responde de inmediato, sino que mantiene la conexión abierta hasta que ocurra un nuevo evento o se agote el tiempo de espera.

\n\n

Imagina que llamas a un amigo y le dices: "Llámame cuando llegue el paquete" — y te quedas al teléfono una hora. Eso es long polling. El polling normal es cuando vuelves a llamar cada 5 minutos: "¿Ya llegó?"

\n\n

Implementación de Long Polling en Rust con Actix-web

\n\n

Escribamos un servidor muy simple en actix-web que use long polling. Tendremos una cola de mensajes — cuando aparece un nuevo mensaje, todos los "esperadores" lo reciben.

\n\n
use actix_web::{web, App, HttpServer, HttpRequest, HttpResponse};\nuse std::sync::Mutex;\nuse tokio::sync::broadcast;\n\nstruct AppState {\n    tx: broadcast::Sender<String>,\n}\n\nasync fn long_poll_handler(data: web::Data<Mutex<AppState>>) -> HttpResponse {\n    let mut rx = {\n        let state = data.lock().unwrap();\n        state.tx.subscribe()\n    };\n\n    // Esperamos un nuevo mensaje durante 30 segundos\n    match tokio::time::timeout(\n        std::time::Duration::from_secs(30),\n        rx.recv()\n    ).await {\n        Ok(Ok(msg)) => HttpResponse::Ok().body(msg),\n        Ok(Err(_)) => HttpResponse::InternalServerError().finish(),\n        Err(_) => HttpResponse::NoContent().finish(), // tiempo de espera agotado\n    }\n}\n\n#[actix_web::main]\nasync fn main() -> std::io::Result<()> {\n    let (tx, _) = broadcast::channel::<String>(100);\n\n    HttpServer::new(move || {\n        App::new()\n            .app_data(web::Data::new(Mutex::new(AppState { tx: tx.clone() })))\n            .route("/poll", web::get().to(long_poll_handler))\n    })\n    .bind("127.0.0.1:8080")?\n    .run()\n    .await\n}
\n\n

El cliente simplemente se quedará colgado en GET /poll. Cuando llegue un mensaje — el servidor responderá. Si no hay nada en 30 segundos — devolverá 204 No Content, y el cliente volverá a solicitar.

\n\n

Ventajas:

\n
    \n
  • Funciona a través de HTTP normal — no se necesitan servidores proxy con soporte WebSocket
  • \n
  • Facilidad de integración con APIs REST existentes
  • \n
  • Ideal para redes corporativas donde los proxies bloquean WebSocket
  • \n
\n\n

Desventajas:

\n
    \n
  • Cada "polling" mantiene una conexión — con 10,000 clientes son 10,000 conexiones TCP abiertas
  • \n
  • Latencia: el cliente igualmente se reconecta después del tiempo de espera
  • \n
  • El servidor gasta recursos manteniendo solicitudes "colgadas"
  • \n
\n\n

WebSocket en Rust: cuando quieres velocidad

\n\n

WebSocket ya no es una "llamada y espera", sino un canal bidireccional completo. El servidor y el cliente pueden intercambiar mensajes en cualquier momento, sin la sobrecarga de los encabezados HTTP.

\n\n

En Rust, el ecosistema WebSocket es rico: tokio-tungstenite para trabajo de bajo nivel, actix-web con soporte integrado

Blogs

Book Recommendations