将FramedRead与侦听器连接一起使用似乎总是没有准备好

时间:2019-04-17 15:43:08

标签: rust-tokio

很抱歉,Rust和Tokio的新手都提出了一个愚蠢的新手问题,但是如果有人能让我知道这是什么/为什么让我感到痛苦,我将不胜感激。我可能可以使用其他方法对此问题进行编码,但我想知道为什么这似乎行不通。

我正在尝试在Tokio中处理一些代码,这些代码创建一个TCP侦听器,然后自动将接收到的JSON转换为Rust结构。似乎使用编解码器可能是一个很好的解决方案,但到目前为止我尝试过的工作似乎无效。

下面是一个最小的程序,我在其中创建了这样的侦听器,只需使用提供的LinesCodec尝试使它解释与它建立的连接:

extern crate tokio;

use std::net::SocketAddr;

use tokio::codec::{LinesCodec, FramedRead};
use tokio::net::TcpListener;
use tokio::prelude::*;

fn main() {
    let addr = "127.0.0.1:12345".parse::<SocketAddr>().unwrap();
    let listener = TcpListener::bind(&addr).unwrap();

    tokio::run(listener.incoming()
        .map_err(|e| eprintln!("failed to accept socket; error = {:?}", e))
        .for_each(move |socket| {
            let transport = FramedRead::new(socket, LinesCodec::new());

            transport.for_each(|msg| {
                println!("Received: {:?}", msg);
                Ok(())
            });

            Ok(())
        })
    );
}

这会编译,当我通过telnet或通过快速python脚本通过发送带换行符的字符串来发送一行时,我再也无法获得期望的打印消息。

编译器会给出有用的警告:

warning: unused `tokio::prelude::stream::ForEach` that must be used
  --> src/main.rs:18:13
   |
18 | /             transport.for_each(|msg| {
19 | |                 println!("Received: {:?}", msg);
20 | |                 Ok(())
21 | |             });
   | |_______________^
   |
   = note: #[warn(unused_must_use)] on by default
   = note: streams do nothing unless polled

所以我尝试如下更改transport.for_each

            let mut stream = transport.for_each(|msg| {
                println!("Received: {:?}", msg);
                Ok(())
            });

            loop {
                match stream.poll() {
                    Ok(s) => {
                        match s {
                            Async::Ready(t) => println!("Ready: {:?}", t),
                            Async::NotReady => println!("Not ready"),
                        }
                    }
                    <snip>
                }
            }

警告现在消失了,我在终端上收到几行说“未准备好”的行。我在做什么错了?

我也尝试使用调试功能来创建自己的基本LinesCodec,但据我所知,它永远不会被调用。然而,根据我在https://tokio.rs/docs/going-deeper/frames/末尾看到的内容,它应该会收到我的消息。

任何帮助将不胜感激,其中包括回答说是从tokio-0.1.18转到0.3.x,因为对您要实现的目标有更好的支持。

1 个答案:

答案 0 :(得分:0)

感谢tokio社区对此提供的帮助。警告是正确的,并且是正确的提示,但是在此处执行轮询不是正确的事情,这将导致它无限期地轮询。相反,我们以item()和error io :: Error结束将来,我们可以使用map_err将其映射到item()和error()到Future中,然后我们可以在该Future上运行tokio :: spawn有效。