【问题标题】:Hyper server drops connection on returning Async::NotReady in Future超级服务器在将来返回 Async::NotReady 时断开连接
【发布时间】:2019-01-18 10:57:04
【问题描述】:

我正在尝试使用未来的请求运行具有异步响应的超级服务器。当调用future 的poll 方法并返回Async::NotReady 时,连接就被断开了(“dropping I/O source: 0”)。我预计poll 方法会被多次调用,直到它返回Async::Ready

example shown 返回一个异步 io 未来,它正在做(我猜)同样的事情。

为什么future的poll函数只调用了一次,为什么在future返回Async::NotReady后hyper会断开连接?

示例代码:(超版本为:v0.12.21)

use futures::{Async, Future, Poll};
use hyper::http::{Request, Response};
use hyper::service::service_fn;
use hyper::{Body, Server};

fn main() {
    let addr = ([127, 0, 0, 1], 3335).into();
    println!("Start request handler. (Listening on http://{})", addr);

    hyper::rt::run(
        Server::bind(&addr)
            .serve(|| service_fn(|request: Request<Body>| handle_request(request.uri().path())))
            .map_err(|e| println!("server error: {}", e)),
    );
}

type BoxedResponseFuture = Box<Future<Item = Response<Body>, Error = tokio::io::Error> + Send>;

fn handle_request(path: &str) -> BoxedResponseFuture {
    println!("Handle request {:?}", path);
    Box::new(
        ResponseFuture { ready: false }
            .and_then(|_| {
                let response = Response::new(Body::from("Success".to_string()));

                Ok(response)
            })
            .or_else(|e| {
                let response = Response::new(Body::from(format!("Error: {:?}", e)));

                Ok(response)
            }),
    )
}

struct ResponseFuture {
    ready: bool,
}

impl Future for ResponseFuture {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        println!("Poll future");

        if self.ready {
            println!("Future ready");

            return Ok(Async::Ready(()));
        }

        println!("Future not ready");
        self.ready = true;
        Ok(Async::NotReady)
    }
}

【问题讨论】:

    标签: rust rust-tokio hyper


    【解决方案1】:

    Hyper 构建在期货箱之上,并使用称为“准备就绪”或“拉动”的未来模型,其中值会根据需要从期货中提取,否则会通知任务当一个值可能准备好被取出时。

    poll 返回NotReady 时,当前任务必须注册准备就绪更改通知,否则任务可能永远无法完成。任何返回Async 的函数都必须遵守它。

    也就是说,你应该等到poll可以返回Ready或者通知当前任务表明它准备好进行进度并返回NotReady

    // notify about progress
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        println!("Poll future");
    
        if self.ready {
            println!("Future ready");
    
            return Ok(Async::Ready(()));
        }
    
        println!("Future not ready");
        self.ready = true;
    
        // The executor will poll this task next iteration
        futures::task::current().notify();
        Ok(Async::NotReady)
    }
    
    // wait until it is Ready
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            println!("Poll future");
    
            if self.ready {
                println!("Future ready");
                return Ok(Async::Ready(()));
            }
    
            println!("Future not ready");
            self.ready = true;
        }
    }
    

    Tokio 的文档 1 2 可能会澄清这一点。

    【讨论】:

    • 感谢您的简短解释。我想我应该更深入地研究 Tokio 的文档。
    猜你喜欢
    • 1970-01-01
    • 2014-11-04
    • 2013-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-21
    • 1970-01-01
    相关资源
    最近更新 更多