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?;
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)
}
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)
}
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%。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