引言:为什么 Rust 是实时应用的理想选择?
\n\n想象一下这个场景:您正在用 Rust 编写一个聊天服务器、股票交易终端或监控系统。用户希望立即收到更新。没有人喜欢手动点击“刷新”按钮——那已经是上个世纪的事了。但是,如何实现从服务器到客户端的数据推送呢?
\n\n很长一段时间里,唯一的方法是 long polling——一个优雅但有点“取巧”的技巧。随后 WebSocket 的出现颠覆了 Web 开发的世界。而现在我们有了 Rust——一种能够在不牺牲内存安全的前提下,从这两种方法中榨取最大性能的语言。
\n\n在本文中,我们不仅会比较 Rust 中的 long polling 和 WebSocket——我们还会编写可运行的示例,启动它们,并深入了解其内部机制。如果您正在用 Rust 编写实时应用,并且在技术选型上犹豫不决,那么您来对地方了。
\n\n通俗理解 Long Polling
\n\nLong polling 是一种技术,客户端向服务器发起一个 HTTP 请求,然后……等待。服务器不会立即响应,而是保持连接打开,直到有新事件发生或超时。
\n\n想象一下,您给朋友打电话说:“包裹到了就给我打电话”——然后您在线等了一个小时。这就是 long polling。普通的 polling 则是您每 5 分钟回拨一次:“喂,到了吗?”
\n\n使用 Actix-web 在 Rust 中实现 Long Polling
\n\n让我们用 actix-web 编写一个最简单的服务器,它使用 long polling。我们会有一个消息队列——当新消息出现时,所有“等待者”都会收到它。
\n\nuse actix_web::{web, App, HttpServer, HttpRequest, HttpResponse};\nuse std::sync::Mutex;\nuse tokio::sync::broadcast;\n\nstruct AppState {\n tx: broadcast::Sender<String>,\n}\n\nasync fn long_poll_handler(data: web::Data<Mutex<AppState>>) -> HttpResponse {\n let mut rx = {\n let state = data.lock().unwrap();\n state.tx.subscribe()\n };\n\n // 等待新消息,最多 30 秒\n match tokio::time::timeout(\n std::time::Duration::from_secs(30),\n rx.recv()\n ).await {\n Ok(Ok(msg)) => HttpResponse::Ok().body(msg),\n Ok(Err(_)) => HttpResponse::InternalServerError().finish(),\n Err(_) => HttpResponse::NoContent().finish(), // 超时\n }\n}\n\n#[actix_web::main]\nasync fn main() -> std::io::Result<()> {\n let (tx, _) = broadcast::channel::<String>(100);\n\n HttpServer::new(move || {\n App::new()\n .app_data(web::Data::new(Mutex::new(AppState { tx: tx.clone() })))\n .route("/poll", web::get().to(long_poll_handler))\n })\n .bind("127.0.0.1:8080")?\n .run()\n .await\n}\n\n客户端只需挂载在 GET /poll 上。当有消息到达时,服务器就会响应。如果 30 秒内没有消息,则返回 204 No Content,客户端会重新发起请求。
优点:
\n- \n
- 通过普通的 HTTP 工作——无需支持 WebSocket 的代理服务器 \n
- 易于与现有的 REST API 集成 \n
- 非常适合代理会阻止 WebSocket 的企业网络环境 \n
缺点:
\n- \n
- 每个“轮询”都保持一个连接——如果有 10,000 个客户端,就有 10,000 个打开的 TCP 连接 \n
- 延迟:客户端在超时后仍需重新连接 \n
- 服务器需要消耗资源来维持“挂起”的请求 \n
Rust 中的 WebSocket:当速度成为关键
\n\nWebSocket 不再是“打电话等待”,而是一个全双工通道。服务器和客户端可以随时交换消息,没有 HTTP 头部的开销。
\n\n在 Rust 生态系统中,WebSocket 资源丰富:tokio-tungstenite 用于底层操作,actix-web 内置了 WebSocket 支持。