Закрытие 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(handle_socket)
}
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!("{}", text),
Message::Close(_) => {
println!("bye");
break;
}
_ => {}
}
}
println!("loop end");
}
После выхода из цикла можно освободить
ресурсы и перестать слать кадры в
этот сокет. Пустой результат чтения
тоже ведет к строке loop end
без отдельного кадра.
Клиент может отправить кадр закрытия перед выходом из программы:
use futures_util::{SinkExt, StreamExt};
use tokio_tungstenite::{connect_async, tungstenite::Message};
#[tokio::main]
async fn main() {
let url = "ws://127.0.0.1:3000";
let (stream, _response) = match connect_async(url).await {
Ok(pair) => pair,
Err(e) => {
eprintln!("{}", e);
return;
}
};
let (mut write, _read) = stream.split();
match write.send(Message::Close(None)).await {
Ok(()) => println!("sent close"),
Err(e) => eprintln!("{}", e),
}
}
Дан текст перед закрытием:
let text = "done";
На клиенте отправьте этот текст,
затем кадр закрытия и выведите
exit после успешной записи
закрытия.
Закрытие:
match msg {
Message::Close(_) => break,
Message::Text(text) => println!("{}", text),
_ => {}
}
Вставьте фрагмент в цикл чтения сервера и скажите, что произойдет, если клиент оборвет сеть без кадра закрытия.
Скажите, почему после break
из цикла чтения не стоит снова
писать в тот же сокет.