Rust上的WebSocket:创建实时应用

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:为什么 Rust 上的 WebSocket 是一对强大的组合



现代 Web 应用越来越需要即时数据传输:聊天、在线游戏、股票行情、通知。传统的 HTTP 及其请求-响应模型在此效率低下——它会带来额外的负载和延迟。WebSocket 协议应运而生,它在客户端和服务器之间建立持久的双向连接。



Rust 语言以其对性能、内存安全和零成本抽象的重视,非常适合构建高负载的实时系统。在本文中,我们将探讨如何使用 tokio-tungstenite 库在 Rust 中构建一个 WebSocket 服务器,并研究实时应用的关键模式。



WebSocket 基础与环境设置



什么是 WebSocket?

WebSocket 是一种基于 TCP 工作的协议。它允许服务器和客户端实时交换消息,无需重复的 HTTP 握手。连接以 HTTP 请求开始,并升级为 WebSocket,之后数据以帧的形式传输。



安装依赖项

为了我们的工作,我们需要 tokio(异步运行时)和 tokio-tungstenite(WebSocket 实现)。创建一个新项目:



cargo new websocket_democd websocket_demo


将依赖项添加到 Cargo.toml:



[dependencies]tokio = { version = "1", features = ["full"] }tokio-tungstenite = "0.21"futures-util = "0.3"


创建一个简单的 WebSocket 服务器



基本的回声服务器

让我们从一个简单的服务器开始,它接受连接并返回收到的消息(回声模式)。这是 WebSocket 的经典 "Hello, World"。



use tokio::net::TcpListener;use tokio_tungstenite::accept_async;use tokio_tungstenite::tungstenite::Message;use futures_util::StreamExt;

#[tokio::main]async fn main() { let addr = "127.0.0.1:8080"; let listener = TcpListener::bind(addr).await.expect("Failed to bind address"); println!("Server started on {}", addr);

while let Ok((stream, peer)) = listener.accept().await { println!("New connection: {}", peer); tokio::spawn(handle_connection(stream)); }}

async fn handle_connection(stream: tokio::net::TcpStream) { let ws_stream = accept_async(stream) .await .expect("Error during WebSocket handshake");

let (_, mut read) = ws_stream.split();

while let Some(msg) = read.next().await { match msg { Ok(Message::Text(text)) => { println!("Received: {}", text); // 这里可以发送响应,但为了简单起见我们跳过 } Ok(Message::Close(_)) => break, _ => {} } }}


这段代码在 8080 端口上启动一个 TCP 服务器。对于每个新连接,会创建一个异步任务 handle_connection,它执行 WebSocket 握手并读取传入的消息。



添加消息发送功能

为了制作一个功能完整的回声服务器,我们需要将流拆分为读取和写入部分。我们使用 futures_util::StreamExt 和 SinkExt:



use futures_util::SinkExt;

async fn handle_connection(stream: tokio::net::TcpStream) { let ws_stream = accept_async(stream) .await .expect("Error during WebSocket handshake");

let (mut write, mut read) = ws_stream.split();

while let Some(msg) = read.next().await { match msg { Ok(Message::Text(text)) => { let echo = format!("Echo: {}", text); write.send(Message::Text(echo.into())).await.unwrap(); } Ok(Message::Close(_)) => break, _ => {} } }}

博客

书籍推荐