WebSockets
Crie clientes WebSocket e servidores independentes com tokio-tungstenite quando não estiver usando o suporte integrado a WebSocket do Axum.
Receita
Cartão de receita de referência rápida - pronto para copiar e colar.
use tokio_tungstenite::connect_async;
use futures_util::{SinkExt, StreamExt};
use tungstenite::Message;
let (ws, _) = connect_async("wss://echo.websocket.events").await?;
let (mut write, mut read) = ws.split();
write.send(Message::Text("hello".into())).await?;
if let Some(Ok(Message::Text(reply))) = read.next().await {
println!("{reply}");
}Quando usar isso: Clientes WebSocket independentes, servidores personalizados ou protocolos fora do Axum.
Exemplo de Trabalho
use futures_util::{SinkExt, StreamExt};
use tokio::net::{TcpListener, TcpStream};
use tokio_tungstenite::accept_async;
use tungstenite::Message;
async fn handle_connection(stream: TcpStream) -> Result<(), Box<dyn std::error::Error>> {
let ws = accept_async(stream).await?;
let (mut write, mut read) = ws.split();
while let Some(msg) = read.next().await {
match msg? {
Message::Text(t) => write.send(Message::Text(format!("echo: {t}").into())).await?,
Message::Close(_) => break,
_ => {}
}
}
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let listener = TcpListener::bind("127.0.0.1:9002").await?;
while let Ok((stream, _)) = listener.accept().await {
tokio::spawn(handle_connection(stream));
}
Ok(())
}O que isso demonstra:
accept_asynccompleta o handshake do lado do servidor em um stream TCP.- Divide o sink/stream para tarefas concorrentes de leitura/escrita, se necessário.
- Lida explicitamente com mensagens
TexteClose. - O cliente usa
connect_asyncsimetricamente.
Mergulho Profundo
Como Funciona
- WebSocket começa como uma requisição HTTP Upgrade.
- Frames carregam opcodes de Texto, Binário, Ping, Pong, Close.
tokio-tungsteniteintegra-se com IO assíncrono do Tokio.
Axum vs tungstenite
| Camada | Ferramenta |
|---|---|
| Rota do Axum | Extrator WebSocketUpgrade |
| Servidor TCP Bruto | tokio-tungstenite::accept_async |
| Cliente | connect_async |
Notas de Rust
// Ping keepalive
write.send(Message::Ping(vec![].into())).await?;Armadilhas
- Sem TLS em accept_async - Apenas TCP puro; envolva com
tokio-rustlspara WSS. Correção: Terminador TLS ou handshake rustls antes de aceitar. - Bombas de tamanho de mensagem - O tamanho máximo padrão da mensagem pode ser excedido maliciosamente. Correção: Configure
max_message_size/max_frame_size. - Conexões meio abertas - O par se foi sem um frame Close. Correção: Ping periódico e timeout de leitura.
- Bloqueio em consumidor lento - Canal ilimitado para o loop de escrita. Correção: Canal limitado com política de descarte.
- Origem não verificada - Vulnerabilidade CSWSH em servidores. Correção: Valide o cabeçalho
Origindurante o handshake.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| Axum WebSocket | Já está no Axum | Bootstrap não-HTTP |
| SSE | Apenas do servidor para o cliente | Chat bidirecional |
| WebTransport | Navegadores modernos, QUIC | Suporte legado amplo necessário |
FAQs
cliente wss?
connect_async para wss:// com conector habilitado para rustls.
Frames binários?
Message::Binary para payloads protobuf ou compactados.
Autenticação?
Token de consulta no upgrade ou cookie na requisição HTTP inicial.
Escalar horizontalmente?
Ponte Redis pub/sub entre instâncias de servidor.
Compressão?
Extensão permessage-deflate - habilite com cuidado para compensação de CPU.
Cliente de teste?
tokio-tungstenite em teste de integração contra servidor local.
Códigos de fechamento?
Envie CloseFrame com motivo para depuração de clientes.
Página do Axum?
Veja WebSockets & SSE em web-backends para o padrão nativo do Axum.
WebSocket HTTP/2?
Raro; a maioria dos WS usa o caminho de upgrade HTTP/1.1.
Timeout ocioso?
tokio::time::timeout em torno de read.next().
Relacionado
- WebSockets & SSE - Integração com Axum
- TLS com rustls - Criptografia WSS
- Sockets de Baixo Nível - TCP sob WS
- Autenticação e Sessões - Protegendo upgrades
- Melhores Práticas de Rede - Operações em tempo real
Versões da Stack: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, e Polars 0.46+.