WebSocket in Rust: tokio-tungstenite and tungstenite libraries

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

WebSocket Libraries for Rust: tungstenite and tokio-tungstenite



WebSocket is a protocol that provides full-duplex communication between a client and a server over a single TCP connection. In the Rust ecosystem, the most popular libraries for working with WebSocket are tungstenite (synchronous) and tokio-tungstenite (asynchronous based on Tokio). Both libraries provide a high-level API for creating WebSocket servers and clients, support standard extensions, and security via TLS.



Key Features

  • tungstenite: synchronous WebSocket implementation (RFC 6455), supports blocking operations, suitable for simple scripts and embedding.
  • tokio-tungstenite: asynchronous wrapper over tungstenite, integrates with the Tokio runtime, allows handling thousands of connections simultaneously.
  • Support for frames, messages, pings/pongs, connection closure.
  • TLS support (via rustls or native-tls).
  • Support for WebSocket extensions (e.g., permessage-deflate compression).
  • Simple setup and minimal dependencies.


Installation

Add the library to Cargo.toml:

[dependencies]tokio-tungstenite = "0.21"       # asynchronous varianttungstenite = "0.21"             # synchronous varianttokio = { version = "1", features = ["full"] }  # for tokio-tungstenite


Example of an Asynchronous WebSocket Server (tokio-tungstenite)

Let's create a simple echo server that receives text messages and sends them back:

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 server started on 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!("Error connecting {}: {}", peer, e); return; } };

let (mut write, mut read) = ws_stream.split(); println!("New connection: {}", peer);

while let Some(msg) = read.next().await { match msg { Ok(Message::Text(text)) => { println!("Received from {}: {}", peer, text); if let Err(e) = write.send(Message::Text(text.into())).await { eprintln!("Error sending: {}", e); break; } } Ok(Message::Close(_)) => { println!("Client {} disconnected", peer); break; } Err(e) => { eprintln!("Error: {}", e); break; } _ => {} // Ignore binary and control messages } }}


Example of a Synchronous WebSocket Client (tungstenite)

A simple client that connects to a server and sends a message:

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!("Connected to server"); println!("HTTP status: {}", response.status());

socket.send(Message::Text("Hello, WebSocket!".into()))?; println!("Message sent");

let msg = socket.read()?; if let Message::T

Recommendations