Следите за новинками
в нашем Telegram канале. Жми, чтобы подписаться:)
⊗rsSpWsSe 273 of 288 menu
◀ ▶

Несколько WebSocket-соединений в Rust

Один прием может обслуживать много переходов подряд. Если обработку держать в том же блоке, что и согласие, второй гость ждет, пока первый закончит читать свой сокет.

Каждый переход можно передать в фоновую задачу: согласие возвращается сразу, а цикл чтения живет отдельно:

use axum::{ extract::ws::{Message, WebSocket, WebSocketUpgrade}, response::IntoResponse, routing::get, Router, }; #[tokio::main] async fn main() { let app = Router::new().route("/", get(ws_entry)); let listener = match tokio::net::TcpListener::bind("127.0.0.1:3000").await { Ok(l) => l, Err(e) => { eprintln!("{}", e); return; } }; match axum::serve(listener, app).await { Ok(()) => {} Err(e) => eprintln!("{}", e), } } async fn ws_entry(ws: WebSocketUpgrade) -> impl IntoResponse { ws.on_upgrade(|socket| async move { tokio::spawn(async move { handle_socket(socket).await; }); }) } async fn handle_socket(mut socket: WebSocket) { loop { let msg = match socket.recv().await { Ok(Some(m)) => m, Ok(None) => break, Err(e) => { eprintln!("{}", e); break; } }; match msg { Message::Text(text) => println!("client {}", text), Message::Close(_) => break, _ => {} } } }

Два клиента могут слать текст одновременно: у каждого свой цикл в своей задаче. Сбой в одном сокете не останавливает прием новых переходов на порту.

Добавим счетчик на экран при старте каждой фоновой обработки:

use std::sync::atomic::{AtomicU64, Ordering}; static NEXT: AtomicU64 = AtomicU64::new(1); async fn ws_entry(ws: WebSocketUpgrade) -> impl IntoResponse { ws.on_upgrade(|socket| async move { let id = NEXT.fetch_add(1, Ordering::Relaxed); tokio::spawn(async move { println!("start {}", id); handle_socket(socket).await; println!("stop {}", id); }); }) }

Дан текст кадра:

let text = "a";

Запустите две клиентские программы и убедитесь, что сервер печатает оба кадра, не дожидаясь конца первого соединения.

Скажите, зачем согласие на переход отдают быстро, а чтение переносят в задачу исполнителя.

Дан порт:

let port = 3000;

Опишите, что произойдет с уже запущенной задачей, если клиент оборвет канал без кадра закрытия.

← →
↑
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить