Rust async 疑问

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 高手帮看下,谢谢:folded_hands:

1 Like

这是期望结果吗

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

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

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

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

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

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

单纯 actix 的 bug 参见 issue

2 Likes