WebSocket в Rust: библиотеки tokio-tungstenite и tungstenite

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Библиотеки 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                    

Рекомендаций