Introdução ao WebSocket em Rust
Aplicações em tempo real (real-time) tornaram-se uma parte essencial da web moderna. Sistemas de chat, jogos online, cotações de bolsa e notificações em tempo real — tudo isso requer troca constante de dados bidirecional entre cliente e servidor. O protocolo WebSocket fornece exatamente essa possibilidade, e Rust, graças ao seu desempenho e segurança, é a linguagem ideal para criar tais sistemas.
Neste artigo, vamos detalhar como criar aplicações em tempo real (real-time) em Rust usando WebSocket. Você aprenderá sobre crates populares, abordagens arquiteturais e obterá exemplos de código prontos para um início rápido.
Fundamentos do WebSocket e escolha de bibliotecas
WebSocket é um protocolo que fornece comunicação full-duplex através de uma única conexão TCP. Diferentemente do HTTP, onde o cliente inicia a requisição e o servidor responde, o WebSocket permite que ambos os lados enviem dados a qualquer momento.
Crates populares para WebSocket em Rust
- tokio-tungstenite — cliente e servidor WebSocket assíncronos baseados em Tokio. Leve e rápido.
- actix-web — um framework web poderoso com suporte integrado a WebSocket.
- tungstenite — versão síncrona, conveniente para cenários simples.
- warp — outro framework assíncrono com suporte a WebSocket.
Para a maioria dos projetos, recomendamos tokio-tungstenite ou actix-web. O primeiro é para servidores e clientes leves, o segundo é para aplicações web completas.
Criando um servidor WebSocket em Rust
Vamos considerar a criação de um servidor echo simples, que recebe mensagens e as envia de volta ao cliente. Usaremos tokio-tungstenite.
Configuração do projeto
Crie um novo projeto Cargo e adicione as dependências no 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 em ws://127.0.0.1:8080");
while let Ok((stream, addr)) = listener.accept().await { println!("Nova conexão: {}", 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(); // Envia a mensagem de volta write.send(msg).await.unwrap(); }} Este código cria um servidor TCP na porta 8080, aceita conexões WebSocket e, para cada cliente, inicia uma tarefa assíncrona que ecoa todas as mensagens recebidas.
Criando um cliente WebSocket em Rust
Agora vamos escrever um cliente que se conecta ao nosso servidor, envia uma mensagem e recebe a resposta.
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 ao servidor");
let (mut write, mut read) = ws_stream.split();
// Envia uma mensagem write.send("Olá, WebSocket!".into()).await?;
// Recebe a resposta if let Some(msg) = read.next().await { let msg = msg?; println!("Recebido: {}", msg.to_text().unwrap()); }
Ok(())} Chat em tempo real (real-time) usando actix-web
Agora co