WebSocket en Rust: bibliotecas tokio-tungstenite y tungstenite

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

Bibliotecas WebSocket para Rust: tungstenite y tokio-tungstenite



WebSocket es un protocolo que proporciona comunicación full-duplex entre cliente y servidor sobre una única conexión TCP. En el ecosistema de Rust, las bibliotecas más populares para trabajar con WebSocket son tungstenite (síncrona) y tokio-tungstenite (asíncrona basada en Tokio). Ambas bibliotecas ofrecen una API de alto nivel para crear servidores y clientes WebSocket, soportan extensiones estándar y seguridad mediante TLS.



Características principales

  • tungstenite: implementación síncrona de WebSocket (RFC 6455), soporta operaciones bloqueantes, adecuada para scripts simples e integración.
  • tokio-tungstenite: envoltura asíncrona sobre tungstenite, se integra con el runtime Tokio, permite manejar miles de conexiones simultáneamente.
  • Soporte de tramas, mensajes, pings/pongs, cierre de conexión.
  • Trabajo con TLS (a través de rustls o native-tls).
  • Soporte de extensiones WebSocket (por ejemplo, compresión permessage-deflate).
  • Configuración sencilla y dependencias mínimas.


Instalación

Agregue la biblioteca a Cargo.toml:

[dependencies]tokio-tungstenite = "0.21"       # variante asíncronatungstenite = "0.21"             # variante síncronatokio = { version = "1", features = ["full"] }  # para tokio-tungstenite


Ejemplo de servidor WebSocket asíncrono (tokio-tungstenite)

Creemos un servidor echo simple que recibe mensajes de texto y los envía de vuelta:

use tokio::net::TcpListener;use tokio_tungstenite::accept_async;use tokio_tungstenite::tungstenite::Message;use futures_util::{SinkExt, StreamExt};

#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { let listener = TcpListener::bind("127.0.0.1:9001").await?; println!("Servidor WebSocket iniciado en ws://127.0.0.1:9001");

while let Ok((stream, peer)) = listener.accept().await { tokio::spawn(handle_connection(stream, peer)); } Ok(())}

async fn handle_connection(stream: tokio::net::TcpStream, peer: std::net::SocketAddr) { let ws_stream = match accept_async(stream).await { Ok(ws) => ws, Err(e) => { eprintln!("Error al conectar {}: {}", peer, e); return; } };

let (mut write, mut read) = ws_stream.split(); println!("Nueva conexión: {}", peer);

while let Some(msg) = read.next().await { match msg { Ok(Message::Text(text)) => { println!("Recibido de {}: {}", peer, text); if let Err(e) = write.send(Message::Text(text.into())).await { eprintln!("Error al enviar: {}", e); break; } } Ok(Message::Close(_)) => { println!("Cliente {} desconectado", peer); break; } Err(e) => { eprintln!("Error: {}", e); break; } _ => {} // Ignoramos mensajes binarios y de control } }}


Ejemplo de cliente WebSocket síncrono (tungstenite)

Un cliente simple que se conecta al servidor y envía un mensaje:

use tungstenite::{connect, Message};use url::Url;

fn main() -> Result<(), Box<dyn std::error::Error>> { let url = Url::parse("ws://echo.websocket.org")?; let (mut socket, response) = connect(url)?;

println!("Conectado al servidor"); println!("Estado HTTP: {}", response.status());

socket.send(Message::Text("¡Hola, WebSocket!".into()))?; println!("Mensaje enviado");

let msg = socket.read()?; if let Message::T

Recommendations