WebSocket библиотеки Rust: tokio-tungstenite и async-tungstenite
WebSocket — это протокол, обеспечивающий двустороннюю связь между клиентом и сервером по одному TCP-соединению. В экосистеме Rust для работы с WebSocket используются две основные библиотеки: tokio-tungstenite (асинхронная на базе Tokio) и async-tungstenite (асинхронная, но с поддержкой разных рантаймов). Обе построены на основе низкоуровневой библиотеки tungstenite, которая реализует сам протокол WebSocket.
Зачем использовать WebSocket в Rust?
Rust — системный язык, который идеально подходит для создания высоконагруженных сетевых приложений. WebSocket библиотеки Rust позволяют:
- Создавать чаты, игры, системы уведомлений в реальном времени
- Обрабатывать тысячи одновременных соединений с минимальным потреблением памяти
- Использовать безопасность памяти Rust на уровне компиляции
- Интегрироваться с другими асинхронными библиотеками (например, с HTTP-серверами)
Установка и настройка
Добавьте зависимость в Cargo.toml:
[dependencies]
tokio = { version = "1", features = ["full"] }
tokio-tungstenite = "0.21"
futures-util = "0.3"
Для async-tungstenite:
[dependencies]
async-tungstenite = "0.25"
async-std = "1.12"
Создание WebSocket клиента на Rust
Пример простого клиента, который подключается к серверу и отправляет сообщение:
use futures_util::{SinkExt, StreamExt};
use tokio_tungstenite::{connect_async, tungstenite::Message};
#[tokio::main]
async fn main() {
let url = "wss://echo.websocket.org";
let (mut ws_stream, _) = connect_async(url).await.expect("Ошибка подключения");
println!("Подключено к серверу");
// Отправляем сообщение
ws_stream.send(Message::Text("Привет, WebSocket!".into())).await.unwrap();
// Получаем ответ
if let Some(msg) = ws_stream.next().await {
let msg = msg.unwrap();
if let Message::Text(text) = msg {
println!("Получено: {}", text);
}
}
ws_stream.close(None).await.unwrap();
}
Создание WebSocket сервера на Rust
Сервер, который принимает соединения и эхо-ответы:
use tokio::net::TcpListener;
use tokio_tungstenite::accept_async;
use futures_util::{SinkExt, StreamExt};
use tokio_tungstenite::tungstenite::Message;
#[tokio::main]
async fn main() {
let listener = TcpListener::bind("127.0.0.1:8080").await.unwrap();
println!("Сервер запущен на ws://127.0.0.1:8080");
while let Ok((stream, addr)) = listener.accept().await {
tokio::spawn(async move {
println!("Новое соединение: {}", addr);
let ws_stream = accept_async(stream).await.unwrap();
let (mut sender, mut receiver) = ws_stream.split();
while let Some(msg) = receiver.next().await {
match msg {
Ok(Message::Text(text)) => {
println!("Сообщение от {}: {}", addr, text);
sender.send(Message::Text(format!("Эхо: {}", text))).await.unwrap();
}
Ok(Message::Close(_)) => break,
_ => {}
}
}
println!("Соединение с {} закрыто", addr);
});
}
}
Основные возможности библиотек
- Поддержка TLS/SSL — защищенные соединения через WSS (требуется включение feature
tls) - Автоматическое переподключение — можно реализовать с помощью циклов и таймеров
- Пинг/понг фреймы — для поддержания соединения
- Бинарные сообщения — работа с
Message::Binary - Разделение на отправителя и получателя — через
.split()
Работа с бинарными данными
Пример отправки и получения бинарных сообщений:
use tokio_tungstenite::tungstenite::Message;
// Отправка бинарных данных
let binary_data = vec![0x00, 0x01, 0x02, 0x03];
ws_stream.send(Message::Binary(binary_data)).await.unwrap();
// Получение бинарных данных
if let Message::Binary(data) = msg {
println!("Получено {} байт", data.len());
}