WebSocket en Rust: creando aplicaciones en 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é WebSocket en Rust es un tándem poderoso



Las aplicaciones web modernas requieren cada vez más transmisión instantánea de datos: chats, juegos en línea, cotizaciones bursátiles, notificaciones. El HTTP tradicional con su modelo de solicitud-respuesta no es eficiente aquí: crea carga y latencia innecesarias. El protocolo WebSocket viene al rescate, estableciendo una conexión bidireccional permanente entre el cliente y el servidor.



El lenguaje Rust con su énfasis en rendimiento, seguridad de memoria y abstracciones de costo cero es ideal para construir sistemas en tiempo real de alta carga. En este artículo, analizaremos cómo construir un servidor WebSocket en Rust usando la biblioteca tokio-tungstenite, y revisaremos los patrones clave para aplicaciones en tiempo real.



Fundamentos de WebSocket y preparación del entorno



¿Qué es WebSocket?

WebSocket es un protocolo que funciona sobre TCP. Permite que el servidor y el cliente intercambien mensajes en tiempo real sin necesidad de handshakes HTTP repetidos. La conexión comienza como una solicitud HTTP con una actualización a WebSocket, después de lo cual los datos se transmiten en tramas.



Instalación de dependencias

Para trabajar necesitaremos tokio (runtime asíncrono) y tokio-tungstenite (implementación de WebSocket). Cree un nuevo proyecto:



cargo new websocket_democd websocket_demo


Agregue las dependencias en Cargo.toml:



[dependencies]tokio = { version = "1", features = ["full"] }tokio-tungstenite = "0.21"futures-util = "0.3"


Creación de un servidor WebSocket simple



Servidor echo básico

Empecemos con un servidor simple que acepta conexiones y envía de vuelta los mensajes recibidos (modo echo). Este es el clásico «Hello, World» para WebSocket.



use tokio::net::TcpListener;use tokio_tungstenite::accept_async;use tokio_tungstenite::tungstenite::Message;use futures_util::StreamExt;

#[tokio::main]async fn main() { let addr = "127.0.0.1:8080"; let listener = TcpListener::bind(addr).await.expect("No se pudo enlazar la dirección"); println!("Servidor iniciado en {}", addr);

while let Ok((stream, peer)) = listener.accept().await { println!("Nueva conexión: {}", peer); tokio::spawn(handle_connection(stream)); }}

async fn handle_connection(stream: tokio::net::TcpStream) { let ws_stream = accept_async(stream) .await .expect("Error en el handshake WebSocket");

let (_, mut read) = ws_stream.split();

while let Some(msg) = read.next().await { match msg { Ok(Message::Text(text)) => { println!("Recibido: {}", text); // Aquí se podría enviar una respuesta, pero por simplicidad lo omitimos } Ok(Message::Close(_)) => break, _ => {} } }}


Este código inicia un servidor TCP en el puerto 8080. Para cada nueva conexión se crea una tarea asíncrona handle_connection, que realiza el handshake WebSocket y lee los mensajes entrantes.



Agregamos envío de mensajes

Para hacer un servidor echo completo, necesitamos dividir el flujo en lectura y escritura. Usamos futures_util::StreamExt y SinkExt:



use futures_util::SinkExt;

async fn handle_connection(stream: tokio::net::TcpStream) { let ws_stream = accept_async(stream) .await .expect("Error en el handshake WebSocket");

let (mut write, mut read) = ws_stream.split();

while let Some(msg) = read.next().await { match msg { Ok(Message::Text(text)) => { let echo = format!("Echo: {}", text); write.send(Message::Text(echo.into())).await.unwrap(); } Ok(Message::Close(_)) => break, _

Blogs

Book Recommendations