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