WebSocket em Rust: criando aplicações em tempo real

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: por que WebSocket em Rust é uma combinação poderosa



Aplicações web modernas cada vez mais exigem transmissão instantânea de dados: chats, jogos online, cotações de bolsa, notificações. O HTTP tradicional com seu modelo de requisição-resposta é ineficiente aqui — ele cria carga e latência desnecessárias. O protocolo WebSocket vem em socorro, estabelecendo uma conexão bidirecional permanente entre cliente e servidor.



A linguagem Rust com seu foco em desempenho, segurança de memória e abstrações de custo zero é ideal para criar sistemas de alta carga em tempo real. Neste artigo, vamos analisar como construir um servidor WebSocket em Rust usando a biblioteca tokio-tungstenite e examinar os principais padrões para aplicações em tempo real.



Fundamentos do WebSocket e preparação do ambiente



O que é WebSocket?

WebSocket é um protocolo que opera sobre TCP. Ele permite que servidor e cliente troquem mensagens em tempo real sem a necessidade de handshakes HTTP repetidos. A conexão começa como uma requisição HTTP com upgrade para WebSocket, após o que os dados são transmitidos em frames.



Instalação de dependências

Para funcionar, precisaremos de tokio (runtime assíncrono) e tokio-tungstenite (implementação WebSocket). Crie um novo projeto:



cargo new websocket_democd websocket_demo


Adicione as dependências no Cargo.toml:



[dependencies]tokio = { version = "1", features = ["full"] }tokio-tungstenite = "0.21"futures-util = "0.3"


Criando um servidor WebSocket simples



Servidor echo básico

Vamos começar com um servidor simples que aceita conexões e envia de volta as mensagens recebidas (modo echo). Este é o clássico "Hello, World" para WebSocket.



use tokio::net::TcpListener;use tokio_tungstenite::accept_async;use tokio_tungstenite::tungstenite::Message;use futures_util::StreamExt;

#[tokio::main]async fn main() { let addr = "127.0.0.1:8080"; let listener = TcpListener::bind(addr).await.expect("Não foi possível vincular o endereço"); println!("Servidor iniciado em {}", addr);

while let Ok((stream, peer)) = listener.accept().await { println!("Nova conexão: {}", peer); tokio::spawn(handle_connection(stream)); }}

async fn handle_connection(stream: tokio::net::TcpStream) { let ws_stream = accept_async(stream) .await .expect("Erro no handshake WebSocket");

let (_, mut read) = ws_stream.split();

while let Some(msg) = read.next().await { match msg { Ok(Message::Text(text)) => { println!("Recebido: {}", text); // Aqui poderia enviar uma resposta, mas por simplicidade vamos pular } Ok(Message::Close(_)) => break, _ => {} } }}


Este código inicia um servidor TCP na porta 8080. Para cada nova conexão, é criada uma tarefa assíncrona handle_connection que realiza o handshake WebSocket e lê as mensagens recebidas.



Adicionando envio de mensagens

Para fazer um servidor echo completo, precisamos dividir o stream em leitura e escrita. Usamos futures_util::StreamExt e SinkExt:



use futures_util::SinkExt;

async fn handle_connection(stream: tokio::net::TcpStream) { let ws_stream = accept_async(stream) .await .expect("Erro no handshake WebSocket");

let (mut write, mut read) = ws_stream.split();

while let Some(msg) = read.next().await { match msg { Ok(Message::Text(text)) => { let echo = format!("Echo: {}", text); write.send(Message::Text(echo.into())).await.unwrap(); } Ok(Message::Close(_)) => break, _

Blogs

Book Recommendations