WebSocket библиотеки Rust: Tokio-tungstenite и async-tungstenite
В современной веб-разработке протокол WebSocket стал стандартом для создания приложений реального времени: чатов, онлайн-игр, финансовых тикеров и систем уведомлений. Экосистема Rust предлагает мощные и безопасные инструменты для работы с WebSocket, среди которых выделяются tokio-tungstenite и async-tungstenite. Эти библиотеки построены на базе популярного асинхронного рантайма Tokio и высокопроизводительного WebSocket-стека tungstenite.
Что такое Tokio-tungstenite и async-tungstenite?
Tokio-tungstenite — это асинхронная WebSocket библиотека для Rust, интегрированная с рантаймом Tokio. Она предоставляет удобные абстракции для создания WebSocket серверов и клиентов, используя стандартные типы Tokio (TcpListener, TcpStream).
Async-tungstenite — это более общая версия, которая работает с любым асинхронным рантаймом (Tokio, async-std, smol) через трейты AsyncRead и AsyncWrite. Обе библиотеки обеспечивают полную поддержку RFC 6455, включая фрагментацию сообщений, ping/pong и маскирование.
Ключевые возможности
- Асинхронность — неблокирующие операции с использованием
async/await - Высокая производительность — минимальные накладные расходы благодаря zero-copy парсингу
- Типобезопасность — сообщения представлены как строго типизированные структуры
- Гибкость — поддержка как серверной, так и клиентской сторон
- SSL/TLS — встроенная поддержка защищенных соединений через
rustlsилиnative-tls - Автоматическое управление соединениями — обработка разрывов и переподключений
Установка
Добавьте в Cargo.toml:
[dependencies]
tokio = { version = "1", features = ["full"] }
tokio-tungstenite = "0.21"
futures-util = "0.3"
Пример: WebSocket сервер
Создадим простой echo-сервер, который отправляет обратно полученное сообщение:
use tokio::net::TcpListener;
use tokio_tungstenite::accept_async;
use futures_util::{SinkExt, StreamExt};
use std::error::Error;
#[tokio::main]
async fn main() -> Result<(), Box> {
let listener = TcpListener::bind("127.0.0.1:8080").await?;
println!("WebSocket сервер запущен на ws://127.0.0.1:8080");
while let Ok((stream, addr)) = listener.accept().await {
println!("Новое подключение: {}", addr);
tokio::spawn(handle_connection(stream));
}
Ok(())
}
async fn handle_connection(stream: tokio::net::TcpStream) {
let ws_stream = accept_async(stream).await.expect("Ошибка handshake");
let (mut write, mut read) = ws_stream.split();
while let Some(Ok(msg)) = read.next().await {
if msg.is_text() || msg.is_binary() {
// Отправляем сообщение обратно
if let Err(e) = write.send(msg).await {
eprintln!("Ошибка отправки: {}", e);
break;
}
}
}
println!("Соединение закрыто");
}
Пример: WebSocket клиент
Подключаемся к серверу и отправляем приветствие:
use tokio_tungstenite::connect_async;
use futures_util::{SinkExt, StreamExt};
use url::Url;
#[tokio::main]
async fn main() -> Result<(), Box> {
let url = Url::parse("ws://127.0.0.1:8080")?;
let (ws_stream, _) = connect_async(url).await?;
println!("Подключено к серверу");
let (mut write, mut read) = ws_stream.split();
// Отправляем сообщение
write.send("Привет, мир!".into()).await?;
println!("Отправлено: Привет, мир!");
// Читаем ответ
if let Some(Ok(msg)) = read.next().await {
println!("Получено: {}", msg.to_text().unwrap());
}
Ok(())
}
Продвинутые возможности
Библиотека поддерживает:
- SSL/TLS — используйте
connect_async_tls_with_configдля защищенных соединений - Кастомные заголовки — передача дополнительных HTTP-заголовков при hand