Rust 目前最高效的 websocket 庫
fastwebsockets 是一個性能高效的實現了 RFC6455 協議的 websocket 庫。
您可以將其用作原始的 websocket 框架解析器,並自己處理規範遵從性問題,也可以將其作爲一個完整的 websocket 客戶端 / 服務器使用。
use fastwebsockets::{Frame, OpCode, WebSocket};
async fn handle_client(
mut socket: TcpStream,
) -> Result<(), WebSocketError> {
handshake(&mut socket).await?;
let mut ws = WebSocket::after_handshake(socket);
ws.set_writev(true);
ws.set_auto_close(true);
ws.set_auto_pong(true);
loop {
let frame = ws.read_frame().await?;
match frame {
OpCode::Close => break,
OpCode::Text | OpCode::Binary => {
let frame = Frame::new(true, frame.opcode, None, frame.payload);
ws.write_frame(frame).await?;
}
}
}
Ok(())
}
默認情況下,fastwebsockets 將爲應用程序提供 FIN 設置的原始幀。其他 Crate,如 tungstenite,會給你一個將所有幀拼裝後的消息。
如果要使用拼裝後的幀,請使用 FragmentCollector:
let mut ws = WebSocket::after_handshake(socket);
let mut ws = FragmentCollector::new(ws);
let incoming = ws.read_frame().await?;
// Always returns full messages
assert!(incoming.fin);
激活 upgrade 特性可以在服務端進行 http 協議升級和客戶端握手處理。
use fastwebsockets::upgrade::upgrade;
use hyper::{Request, body::{Incoming, Bytes}, Response};
use http_body_util::Empty;
use anyhow::Result;
async fn server_upgrade(
mut req: Request<Incoming>,
) -> Result<Response<Empty<Bytes>>> {
let (response, fut) = upgrade::upgrade(&mut req)?;
tokio::spawn(async move {
if let Err(e) = handle_client(fut).await {
eprintln!("Error in websocket connection: {}", e);
}
});
Ok(response)
}
使用 handshake 模塊處理客戶端握手。
use fastwebsockets::handshake;
use fastwebsockets::WebSocket;
use hyper::{Request, body::Bytes, upgrade::Upgraded, header::{UPGRADE, CONNECTION}};
use http_body_util::Empty;
use tokio::net::TcpStream;
use std::future::Future;
use anyhow::Result;
async fn connect() -> Result<WebSocket<Upgraded>> {
let stream = TcpStream::connect("localhost:9001").await?;
let req = Request::builder()
.method("GET")
.uri("http://localhost:9001/")
.header("Host", "localhost:9001")
.header(UPGRADE, "websocket")
.header(CONNECTION, "upgrade")
.header(
"Sec-WebSocket-Key",
fastwebsockets::handshake::generate_key(),
)
.header("Sec-WebSocket-Version", "13")
.body(Empty::<Bytes>::new())?;
let (ws, _) = handshake::client(&SpawnExecutor, req, stream).await?;
Ok(ws)
}
// Tie hyper's executor to tokio runtime
struct SpawnExecutor;
impl<Fut> hyper::rt::Executor<Fut> for SpawnExecutor
where
Fut: Future + Send + 'static,
Fut::Output: Send + 'static,
{
fn execute(&self, fut: Fut) {
tokio::task::spawn(fut);
}
}
fastwebsockets 性能非常高效,可以和 uWebSockets(C++ 開發)比肩,和 Rust 的同類 Websocket 庫 tokio-tungstenite 相比,性能超出約 30%。
Y 軸表示每秒發送的消息數量,Y 軸越高越好。
使用的測試機配置:
Linux divy 5.19.0-1022-gcp #24~22.04.1-Ubuntu SMP x86_64 GNU/Linux
32GiB System memory
Intel(R) Xeon(R) CPU @ 3.10GHz
fastwebsockets 0.4.2
rust-websocket 0.26.5
uWebSockets (main d043038)
tokio-tungstenite 0.18.0
如果你需要性能高效的 Websocket 庫,請選擇 fastwebsockets。
Github 地址:https://github.com/denoland/fastwebsockets
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/9aQz5aTyPW4K7-tzTtTLVg