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 eficienteMensajería con broadcast para comunicación en tiempo realManejo 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!