39 - Construyendo una aplicación asíncrona - un servidor de chat en Rust

39 - Construyendo una aplicación asíncrona - un servidor de chat en Rust

¡Bienvenidos de nuevo a Rustaceo.es! Hoy construiremos un servidor de chat asíncrono en Rust, utilizando tokio para manejar múltiples conexiones sin bloquear el sistema. Aprenderemos a enviar y recibir mensajes en tiempo real, asegurando una comunicación eficiente entre clientes.


🚀 Objetivos del proyecto #

  1. Manejar múltiples clientes concurrentemente usando Tokio.
  2. Implementar comunicación bidireccional con tokio::sync::broadcast.
  3. Crear un servidor TCP asíncrono para gestionar clientes en tiempo real.

⚡ Configuración del proyecto #

Primero, inicializamos un nuevo proyecto con Tokio:

cargo new async-chat-server --bin
cd async-chat-server

Luego, agregamos Tokio en Cargo.toml:

[dependencies]
tokio = { version = "1", features = ["full"] }

🏗 Implementando el servidor de chat #

📌 Configuración del servidor tcp #

use tokio::net::{TcpListener, TcpStream};
use tokio::sync::broadcast;
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use std::sync::Arc;

#[Tokio::main]
async fn main() {
    let listener = TcpListener::bind("127.0.0.1:8080").await.unwrap();
    let (tx, _rx) = broadcast::channel(10);
    println!("Servidor de chat iniciado en 127.0.0.1:8080");
    
    loop {
        let (socket, _) = listener.accept().await.unwrap();
        let tx = tx.clone();
        let rx = tx.subscribe();
        tokio::spawn(async move {
            manejar_cliente(socket, tx, rx).await;
        });
    }
}

🔹 TcpListener::bind: Inicia un servidor TCP en el puerto 8080. 🔹 broadcast::channel(10): Canal de transmisión para enviar mensajes a múltiples clientes. 🔹 tokio::spawn: Lanza cada cliente en una tarea separada para manejar múltiples conexiones simultáneamente.


📬 Manejo de clientes y mensajes #

async fn manejar_cliente(socket: TcpStream, tx: broadcast::Sender<String>, mut rx: broadcast::Receiver<String>) {
    let mut reader = BufReader::new(socket);
    let mut line = String::new();
    let (mut reader, mut writer) = reader.split();

    tokio::spawn(async move {
        while let Ok(msg) = rx.recv().await {
            writer.write_all(msg.as_bytes()).await.unwrap();
        }
    });

    while reader.read_line(&mut line).await.unwrap() > 0 {
        let mensaje = line.trim().to_string();
        tx.send(mensaje.clone()).unwrap();
        line.clear();
    }
}

🔹 rx.recv().await: Recibe mensajes de otros clientes y los envía al cliente actual. 🔹 reader.read_line().await: Espera mensajes del cliente y los retransmite a todos. 🔹 tx.send(): Envía el mensaje a todos los suscriptores del canal.


🏆 Probando el servidor de chat #

Para probar el servidor, ejecutamos:

cargo run

Luego, podemos conectarnos con nc en múltiples terminales:

nc 127.0.0.1 8080

Cada mensaje enviado se retransmitirá a todos los clientes conectados.


📌 Conclusión #

Hemos construido un servidor de chat asíncrono en Rust que permite múltiples clientes simultáneos sin bloquear el sistema.

✔ Tokio para concurrencia eficiente ✔ Mensajería con broadcast para comunicación en tiempo real ✔ Manejo seguro de múltiples clientes en un entorno asíncrono

🔮 Próximo paso: Implementar autenticación y cifrado en la comunicación.

¡Nos vemos en la siguiente entrega, Rustaceos!