聊天室实战 #

项目结构 #

text
chat-app/
├── Cargo.toml
├── src/
│   └── main.rs
└── static/
    └── index.html

服务端实现 #

rust
use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer, Responder};
use actix_ws::{Message, Session};
use std::collections::HashSet;
use std::sync::{Arc, Mutex};
use tokio::sync::broadcast;

struct ChatState {
    tx: broadcast::Sender<String>,
    users: Mutex<HashSet<String>>,
}

async fn ws_chat(
    req: HttpRequest,
    body: web::Payload,
    state: web::Data<Arc<ChatState>>,
) -> Result<HttpResponse, Error> {
    let (response, mut session, mut msg_stream) = actix_ws::handle(&req, body)?;
    
    let tx = state.tx.clone();
    let mut rx = tx.subscribe();
    
    actix_web::rt::spawn(async move {
        loop {
            tokio::select! {
                Some(msg_result) = msg_stream.next() => {
                    match msg_result {
                        Ok(Message::Text(text)) => {
                            let _ = tx.send(text.to_string());
                        }
                        Ok(Message::Close(_)) => {
                            session.close(None).await.unwrap();
                            return;
                        }
                        _ => {}
                    }
                }
                Ok(msg) = rx.recv() => {
                    session.text(msg).await.unwrap();
                }
            }
        }
    });
    
    Ok(response)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let (tx, _) = broadcast::channel(100);
    
    let state = Arc::new(ChatState {
        tx,
        users: Mutex::new(HashSet::new()),
    });
    
    HttpServer::new(move || {
        App::new()
            .app_data(web::Data::new(state.clone()))
            .route("/ws", web::get().to(ws_chat))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

客户端实现 #

html
<!DOCTYPE html>
<html>
<head>
    <title>Chat Room</title>
</head>
<body>
    <div id="messages"></div>
    <input type="text" id="input" />
    <button onclick="send()">Send</button>
    
    <script>
        const ws = new WebSocket('ws://localhost:8080/ws');
        const messages = document.getElementById('messages');
        
        ws.onmessage = (event) => {
            const div = document.createElement('div');
            div.textContent = event.data;
            messages.appendChild(div);
        };
        
        function send() {
            const input = document.getElementById('input');
            ws.send(input.value);
            input.value = '';
        }
    </script>
</body>
</html>

下一步 #

继续学习 测试,了解应用测试!

最后更新:2026-03-29