Библиотеки WebSocket для Rust: tungstenite и tokio-tungstenite
WebSocket — это протокол, обеспечивающий полнодуплексную связь между клиентом и сервером поверх одного TCP-соединения. В экосистеме Rust наиболее популярными библиотеками для работы с WebSocket являются tungstenite (синхронная) и tokio-tungstenite (асинхронная на базе Tokio). Обе библиотеки предоставляют высокоуровневый API для создания WebSocket-серверов и клиентов, поддерживают стандартные расширения и безопасность через TLS.
Основные возможности
- tungstenite: синхронная реализация WebSocket (RFC 6455), поддерживает блокирующие операции, подходит для простых скриптов и встраивания.
- tokio-tungstenite: асинхронная обёртка поверх tungstenite, интегрируется с рантаймом Tokio, позволяет обрабатывать тысячи соединений одновременно.
- Поддержка фреймов, сообщений, пингов/понгов, закрытия соединения.
- Работа с TLS (через
rustlsилиnative-tls). - Поддержка WebSocket-расширений (например, сжатие permessage-deflate).
- Простая настройка и минимальные зависимости.
Установка
Добавьте библиотеку в Cargo.toml:
[dependencies]
tokio-tungstenite = "0.21" # асинхронный вариант
tungstenite = "0.21" # синхронный вариант
tokio = { version = "1", features = ["full"] } # для tokio-tungstenite
Пример асинхронного WebSocket-сервера (tokio-tungstenite)
Создадим простой эхо-сервер, который принимает текстовые сообщения и отправляет их обратно:
use tokio::net::TcpListener;
use tokio_tungstenite::accept_async;
use tokio_tungstenite::tungstenite::Message;
use futures_util::{SinkExt, StreamExt};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let listener = TcpListener::bind("127.0.0.1:9001").await?;
println!("WebSocket сервер запущен на ws://127.0.0.1:9001");
while let Ok((stream, peer)) = listener.accept().await {
tokio::spawn(handle_connection(stream, peer));
}
Ok(())
}
async fn handle_connection(stream: tokio::net::TcpStream, peer: std::net::SocketAddr) {
let ws_stream = match accept_async(stream).await {
Ok(ws) => ws,
Err(e) => {
eprintln!("Ошибка при подключении {}: {}", peer, e);
return;
}
};
let (mut write, mut read) = ws_stream.split();
println!("Новое подключение: {}", peer);
while let Some(msg) = read.next().await {
match msg {
Ok(Message::Text(text)) => {
println!("Получено от {}: {}", peer, text);
if let Err(e) = write.send(Message::Text(text.into())).await {
eprintln!("Ошибка отправки: {}", e);
break;
}
}
Ok(Message::Close(_)) => {
println!("Клиент {} отключился", peer);
break;
}
Err(e) => {
eprintln!("Ошибка: {}", e);
break;
}
_ => {} // Игнорируем бинарные и контрольные сообщения
}
}
}
Пример синхронного WebSocket-клиента (tungstenite)
Простой клиент, который подключается к серверу и отправляет сообщение:
use tungstenite::{connect, Message};
use url::Url;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let url = Url::parse("ws://echo.websocket.org")?;
let (mut socket, response) = connect(url)?;
println!("Подключено к серверу");
println!("HTTP статус: {}", response.status());
socket.send(Message::Text("Привет, WebSocket!".into()))?;
println!("Отправлено сообщение");
let msg = socket.read()?;
if let Message::Text(text) = msg {
println!("Получен ответ: {}", text);
}
socket.close(None)?;
Ok(())
}
Асинхронный WebSocket-клиент с Tokio
Клиент на tokio-tungstenite, который подключается к серверу и обменивается сообщениями:
use tokio_tungstenite::connect_async;
use tokio_tungstenite::tungstenite::Message;
use futures_util::{SinkExt, StreamExt};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let url = url::Url::parse("wss://echo.websocket.org")?;
let (ws Также в библиотеке
Работа с CSV в Java: библиотеки OpenCSV и Apache Commons CSV
Очереди задач для PHP: RabbitMQ, Gearman и Redis
Работа с Markdown в TypeScript: библиотеки, парсеры и инструменты
openapi-typescript для TypeScript: полное руководство с примерами
Работа с S3 и облачными хранилищами в C++: библиотека aws-sdk-cpp