首页 > 解决方案 > 如何使用超体通道?

问题描述

我正在尝试使用 Hyper 库发出 POST HTTP 请求,然后将数据写入其中,直到我关闭它(从多个函数/线程)。我在文档中找到了可以Body::channel()用来执行此操作的文档,但我使用不当,因为我只能写入通道一次。我还没有找到任何例子,有人可以指出我正确的方向吗?

let (mut sender, body) = Body::channel();

let request = Request::builder()
    .method(Method::POST)
    .uri("http://localhost:3000/")
    .header("content-type", "text")
    .body(body)
    .unwrap();

let client = Client::new();
let response = client.request(request);

//Does get sent
println!("Body: {:?}", sender.send_data(hyper::body::Bytes::from("test\n")).await);
//Stuck on this one
println!("Body: {:?}", sender.send_data(hyper::body::Bytes::from("test2\n")).await);
//Debug print
println!("{:?}", response.await);

标签: httppostrusthyper

解决方案


您需要将send_data()行包装在tokio::spawn(async move { ... });.

问题是Body/Sender只有缓冲区大小为 1。所以第二次send_data()调用导致它await(内部)直到Sender准备好。这就是随后导致它“卡住”的原因。

这可以通过使用解决,tokio::spawn()因为它最终允许awaiting ResponseFuture,这会导致请求被执行。

let (sender, body) = Body::channel();

let request = Request::builder()
    .method(Method::POST)
    .uri("http://localhost:3000/")
    .header("content-type", "text")
    .body(body)
    .unwrap();

let client = Client::new();

let response = client.request(request);

tokio::spawn(async move {
    let mut sender = sender;

    println!("Body: {:?}", sender.send_data(hyper::body::Bytes::from("test\n")).await);
    println!("Body: {:?}", sender.send_data(hyper::body::Bytes::from("test2\n")).await);
});

println!("{:?}", response.await);

文档中没有提到缓冲区大小(据我所知)。但是,您可以通过检查与相关的源Body::channel()来弄清楚这一点,您可以在其中看到它使用futures_channel::mpsc::channel(0). 文档提到缓冲区大小是buffer + num-senders,在我们的例子中是0 + 1


推荐阅读