Introducción a WebSocket en Rust
Las aplicaciones en tiempo real se han convertido en una parte esencial de la web moderna. Sistemas de chat, juegos en línea, cotizaciones bursátiles y notificaciones en tiempo real — todo esto requiere un intercambio bidireccional constante de datos entre el cliente y el servidor. El protocolo WebSocket proporciona precisamente esta capacidad, y Rust, gracias a su rendimiento y seguridad, es el lenguaje ideal para crear dichos sistemas.
En este artículo, analizaremos en detalle cómo crear aplicaciones en tiempo real en Rust utilizando WebSocket. Conocerás las crates populares, los enfoques arquitectónicos y obtendrás ejemplos de código listos para un inicio rápido.
Fundamentos de WebSocket y selección de bibliotecas
WebSocket es un protocolo que proporciona comunicación full-duplex a través de una única conexión TCP. A diferencia de HTTP, donde el cliente inicia una solicitud y el servidor responde, WebSocket permite que ambas partes envíen datos en cualquier momento.
Crates populares para WebSocket en Rust
- tokio-tungstenite — Cliente y servidor WebSocket asíncronos basados en Tokio. Ligero y rápido.
- actix-web — Potente framework web con soporte integrado para WebSocket.
- tungstenite — Versión síncrona, conveniente para escenarios simples.
- warp — Otro framework asíncrono con soporte para WebSocket.
Para la mayoría de los proyectos, recomendamos tokio-tungstenite o actix-web. El primero es para servidores y clientes ligeros, el segundo para aplicaciones web completas.
Creación de un servidor WebSocket en Rust
Consideremos la creación de un servidor echo simple, que recibe mensajes y los envía de vuelta al cliente. Usaremos tokio-tungstenite.
Configuración del proyecto
Crea un nuevo proyecto Cargo y agrega las dependencias en Cargo.toml:
[dependencies]tokio = { version = "1", features = ["full"] }tokio-tungstenite = "0.21"futures-util = "0.3"Servidor echo básico
use futures_util::{SinkExt, StreamExt};use tokio::net::TcpListener;use tokio_tungstenite::accept_async;
#[tokio::main]async fn main() -> Result<(), Box> { let listener = TcpListener::bind("127.0.0.1:8080").await?; println!("Servidor iniciado en ws://127.0.0.1:8080");
while let Ok((stream, addr)) = listener.accept().await { println!("Nueva conexión: {}", addr); tokio::spawn(handle_connection(stream)); }
Ok(())}
async fn handle_connection(stream: tokio::net::TcpStream) { let ws_stream = accept_async(stream).await.unwrap(); let (mut write, mut read) = ws_stream.split();
while let Some(msg) = read.next().await { let msg = msg.unwrap(); // Enviamos el mensaje de vuelta write.send(msg).await.unwrap(); }} Este código crea un servidor TCP en el puerto 8080, acepta conexiones WebSocket y para cada cliente inicia una tarea asíncrona que repite como eco todos los mensajes entrantes.
Creación de un cliente WebSocket en Rust
Ahora escribamos un cliente que se conecte a nuestro servidor, envíe un mensaje y reciba la respuesta.
use futures_util::StreamExt;use tokio_tungstenite::connect_async;
#[tokio::main]async fn main() -> Result<(), Box> { let url = "ws://127.0.0.1:8080"; let (ws_stream, _) = connect_async(url).await?;
println!("Conectado al servidor");
let (mut write, mut read) = ws_stream.split();
// Enviamos un mensaje write.send("¡Hola, WebSocket!".into()).await?;
// Recibimos la respuesta if let Some(msg) = read.next().await { let msg = msg?; println!("Recibido: {}", msg.to_text().unwrap()); }
Ok(())} Chat en tiempo real usando actix-web
Ahora co