Rust async 疑问

问答 347 views 6 replies
admin #1 ·
use actix_web::{
    dev::ServiceRequest, error::ErrorUnauthorized, App, Error as ActixError,
    HttpServer,
};
use actix_web_httpauth::extractors::basic::BasicAuth;
use std::io;
use std::time::Duration;
use tokio::sync::oneshot;

async fn do_auth(
    req: ServiceRequest,
    creds: BasicAuth,
) -> Result<ServiceRequest, (ActixError, ServiceRequest)> {
    if creds.user_id() == "user" && creds.password() == Some("22222222222222222222") {
        Ok(req)
    } else {
        Err((ErrorUnauthorized("not authorized"), req))
    }
}

async fn process(socket: tokio::net::TcpStream) {
    // Process the socket connection
    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
    println!("Processing socket connection");
}

#[tokio::main(flavor = "current_thread")]
async fn main() -> io::Result<()> {
    {
        let (tx, rx) = oneshot::channel();

        tokio::spawn(async move {
            tokio::time::sleep(Duration::from_secs(2)).await;
            tx.send(()).unwrap();
        });

        let server = HttpServer::new(|| {
            App::new()
                // .wrap(HttpAuthentication::basic(do_auth))
                .service(
                    actix_files::Files::new("/", "/storage/emulated/0/")
                        .show_files_listing()
                        .use_hidden_files(),
                )
        })
        .shutdown_timeout(1)
        .bind(("0.0.0.0", 4804))
        .unwrap()
        .run();
        let server_handle = server.handle();

        tokio::select! {
                _ = async {
                    server.await.unwrap();
                    // Help the rust type inferencer out
                    Ok::<_,std::io::Error>(())
                } => {}
            _ = rx => {
                println!("terminating accept loop");
                server_handle.stop(false).await;
            }
        }
    }

    println!("sleeping");
    tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;
    println!("exiting");
    Ok(())
}

[package]
name = "tmptokio"
version = "0.1.0"
edition = "2024"

[dependencies]
tokio = { version = "1", features = ["full"] }
actix-files = "0.6.6"
actix-web = { version = "4", features = ["macros", "compress-brotli", "compress-gzip", "compress-zstd"], default-features = false }
actix-web-httpauth = "0.8"

为啥 server_handle.stop(false).await; 不起作用呢?

在 print sleep 之后,http server 还在运行
有没有 Rust 高手帮看下,谢谢🙏

❤️
1
mod #2 ·

image

这是期望结果吗

admin #3 ·
emu_otori 鳳 笑夢

这段代码编译无问题,只看输出不够,netstat 看端口是否还在监听或 curl 看看,sleep 后 exit 前 server 依然还在

mod #4 ·
I
IO

这,运行几秒后已经自动退出了,怎么可能还在监听

tokio select 阻塞住两秒,然后收到 oneshot signal 打印 terminating accept loop 并停止服务器。然后打印 sleeping 并睡眠三秒,再打印 exiting。

出现 sleeping 前服务器一定已经停止了,因为顺序执行的

admin #5 ·
emu_otori 鳳 笑夢

curl 看看哦,和预想的不一样

mod #6 ·
I
IO

sleeping 前面的大括号结束的时候 server 应该已经被 drop 掉了,但还能继续响应请求,说明应该不是 await 的问题。

#7 ·

单纯 actix 的 bug 参见 issue

❤️
2