Rust:安全的单线程 TCP 服务器

Rust: Safe single-threaded TCP Server

是否可以在纯 Rust 中编写单线程 TCP 服务器? 在 C 中,我会使用 select 系统调用来“监听”多个套接字。 我只找到人们使用 unsafe to use epoll/select 的解决方案,但我真的想避免这种情况。我认为这是一项基本任务,我无法想象没有纯 Rust 解决方案来解决这样的任务。 基本上我在标准库中寻找抽象。

这是我想要的 C 语言: https://www.gnu.org/software/libc/manual/html_node/Server-Example.html

例如与 select/epoll 一起使用不安全: https://www.zupzup.org/epoll-with-rust/index.html

select 和朋友是系统调用。要使用 select 和朋友,在某一时刻,Rust 需要调用这些系统调用。这些系统调用没有用 Rust 表达,它们使用 C 语义(当通过 libc 调用它们时)或汇编(当直接调用它们时)。

从 Rust 的角度来看,这意味着它们是不安全的,Rust 编译器根本无法知道它们在做什么。

这意味着为了从生锈中使用它们,您有两个选择:

  • 直接调用它们,使用 unsafe
  • 或者使用最终调用它们的更高级别的包(内部使用不安全的),比如 tokio

即使存在(linux-仅)纯 Rust 和针对 Rust 的 reinvention libc,它最终还是必须使用 unsafe 为了制作实际的系统调用并调用内核。假设的纯铁锈裸机 unikernel 也是如此。

我最终使用了 async/await。在这个例子中没有正确的错误处理。

use async_std::net::TcpListener;
use async_std::task;
use async_tungstenite::accept_async;
use futures::{
    SinkExt,
    StreamExt,
};
use std::net::SocketAddr;
use std::str::FromStr;


async fn run() {
    let addrs = [
        SocketAddr::from_str("0.0.0.0:9001").unwrap(),
        SocketAddr::from_str("[::]:9001").unwrap()];
    let listener = TcpListener::bind(&addrs[..]).await.unwrap();

    listener.incoming().for_each_concurrent(None, |stream| async move {
        let mut websocket = accept_async(stream.unwrap()).await.unwrap();
        loop {
            let msg = websocket.next().await.unwrap().unwrap();
            println!("Received {}", msg);
            if msg.is_binary() || msg.is_text() {
                websocket.send(msg).await.unwrap();
            }
        }
    }).await;
}


fn main () {
    task::block_on(run());
}