Jesse Lawson


Axum WebSocket echo server

This is a minimum working example (MWE) of a WebSocket echo server in Rust using axum and tokio.

The HTTPS handshake happens on the same route (/) as the WebSocket connection.

This MWE uses the following dependencies in Cargo.toml:

[dependencies]
axum = {version = "0.7.9", features = ["ws"]}
tokio = {version = "1.41.1", features = ["full"]}

The following resides in src/main.rs:

1use axum::{
2 response::Response,
3 routing::get,
4 Router,
5 // Include the WebSocketUpgrade extractor:
6 extract::ws::{WebSocket, WebSocketUpgrade},
7};
8use tokio;
9
10// When a request comes in with the "Upgrade: websocket" header,
11// you'll have `Some(ws)`. For regular HTTP requests, it will
12// be `None`:
13async fn handler(ws: Option<WebSocketUpgrade>) -> Response {
14 if let Some(ws) = ws {
15 // Handle WebSocket connection
16 ws.on_upgrade(handle_socket)
17 } else {
18 // Handle HTTP request
19 Response::new("Hello HTTP!".into())
20 }
21}
22
23// Basic echo server example:
24async fn handle_socket(mut socket: WebSocket) {
25 while let Some(msg) = socket.recv().await {
26 if let Ok(msg) = msg {
27 if let Err(_) = socket.send(msg).await {
28 break;
29 }
30 }
31 }
32}
33
34#[tokio::main]
35async fn main() {
36 let app = Router::new()
37 // Pass the handler that includes the `WebSocketUpgrade` extractor to your route:
38 .route("/", get(handler));
39
40 let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await.unwrap();
41 axum::serve(listener, app).await.unwrap();
42}
43