Setup

# Cargo.toml
[dependencies]
tokio = { version = "1", features = ["full"] }
tokio-tungstenite = "0.21"
futures-util = "0.3"

Library Choice

Library Type Use Case
tokio-tungstenite Async Production apps, multiple connections
tungstenite Sync Simple scripts, single connection

Use async when you need to multiplex many socket connections on a single thread — essential for trading infra.


Client — connect_async

Simplest way to connect. Handles DNS, TCP, TLS, and handshake for you.

use tokio_tungstenite::{connect_async, tungstenite::Message};
use futures_util::{SinkExt, StreamExt};

#[tokio::main]
async fn main() {
    let url = "wss://[stream.binance.com:9443/ws/btcusdt@trade](<http://stream.binance.com:9443/ws/btcusdt@trade>)";
    
    let (ws_stream, _response) = connect_async(url)
        .await
        .expect("Failed to connect");
    
    let (mut write, mut read) = ws_stream.split();
    
    // Send a message
    write.send(Message::Text("Hello".into())).await.unwrap();
    
    // Receive messages
    while let Some(msg) = [read.next](<http://read.next>)().await {
        match msg {
            Ok(Message::Text(text)) => println!("Received: {}", text),
            Ok(Message::Ping(data)) => {
                write.send(Message::Pong(data)).await.unwrap();
            }
            Ok(Message::Close(_)) => {
                println!("Connection closed");
                break;
            }
            Err(e) => eprintln!("Error: {}", e),
            _ => {}
        }
    }
}

Function Families

Function Role TCP Connection When to Use
connect_async Client Creates for you Simple client — just give URL
client_async Client You provide Need custom TCP (pooling, proxy)
accept_async Server You provide Building a WebSocket server

client_async — Pre-existing Stream

// When you already have a TCP stream
let tcp_stream = TcpStream::connect("[example.com:443](<http://example.com:443>)").await?;
let (ws, _) = client_async("wss://[example.com/ws](<http://example.com/ws>)", tcp_stream).await?;

accept_async — Server Side

// You're the SERVER accepting connections
let listener = TcpListener::bind("127.0.0.1:8080").await?;
let (tcp_stream, _) = listener.accept().await?;
let ws = accept_async(tcp_stream).await?;  // Upgrade TCP → WebSocket

Message Types

enum Message {
    Text(String),      // UTF-8 text
    Binary(Vec<u8>),   // Raw bytes
    Ping(Vec<u8>),     // Heartbeat request
    Pong(Vec<u8>),     // Heartbeat response
    Close(Option<CloseFrame>),
}