【问题标题】:How can I read non-blocking from stdin?如何从标准输入读取非阻塞?
【发布时间】:2015-05-03 10:56:04
【问题描述】:

有没有办法在 Rust 中检查 stdin 上的数据是否可用,或者进行读取并立即返回当前可用的数据?

我的目标是能够读取例如通过设置为立即返回所有读取数据的外壳中的光标键产生的输入。例如等效于:stty -echo -echok -icanon min 1 time 0

我想一种解决方案是使用 ncurses 或类似的库,但我想避免任何类型的大依赖。

到目前为止,我只得到了阻塞输入,这不是我想要的:

let mut reader = stdin();
let mut s = String::new();

match reader.read_to_string(&mut s) {...} // this blocks :(

【问题讨论】:

    标签: rust


    【解决方案1】:

    将 OP 的评论转化为答案:

    您可以生成一个线程并通过channel 发送数据。然后,您可以使用try_recv 在主线程中轮询该通道。

    use std::io;
    use std::sync::mpsc;
    use std::sync::mpsc::Receiver;
    use std::sync::mpsc::TryRecvError;
    use std::{thread, time};
    
    fn main() {
        let stdin_channel = spawn_stdin_channel();
        loop {
            match stdin_channel.try_recv() {
                Ok(key) => println!("Received: {}", key),
                Err(TryRecvError::Empty) => println!("Channel empty"),
                Err(TryRecvError::Disconnected) => panic!("Channel disconnected"),
            }
            sleep(1000);
        }
    }
    
    fn spawn_stdin_channel() -> Receiver<String> {
        let (tx, rx) = mpsc::channel::<String>();
        thread::spawn(move || loop {
            let mut buffer = String::new();
            io::stdin().read_line(&mut buffer).unwrap();
            tx.send(buffer).unwrap();
        });
        rx
    }
    
    fn sleep(millis: u64) {
        let duration = time::Duration::from_millis(millis);
        thread::sleep(duration);
    }
    

    【讨论】:

    • 太棒了!多线程是 Rust 的强项。
    【解决方案2】:

    大多数操作系统默认以阻塞方式使用标准输入和输出。难怪Rust 库会取而代之。

    要以非阻塞方式从阻塞流中读取,您可以创建一个单独的线程,以便额外线程阻塞而不是主线程。检查阻塞文件描述符是否产生了一些输入是类似的:产生一个线程,让它读取数据,检查它是否产生了任何数据。

    Here's 我使用的一段代码具有类似的目标,即交互式处理管道输出,希望可以作为示例。它通过channel 发送数据,它支持try_recv 方法 - 允许您检查数据是否可用。

    Someone has told me mio 可能用于以非阻塞方式从管道读取,因此您可能也想检查一下。我怀疑将标准输入文件描述符 (0) 传递给 PipeReader::from_fd 应该可以正常工作。

    【讨论】:

    • pub fn init() -> Receiver { let (tx, rx) = channel::(); thread::spawn(move|| { while true { tx.send(read_stdin()); } }); rx } pub fn get(rx: &Receiver, old: ControlKeys) -> ControlKeys { match rx.try_recv() { Ok(key) => key, Err(_) => old } } fn read_stdin() - > ControlKeys { 让 mut reader = stdin();让 mut buf = &mut [0u8; 10]; match reader.read(buf) { Err(why) => panic!(...), Ok(size) => { // 读取 buf 返回 res; } } }
    【解决方案3】:

    您还可以考虑使用ncurses(也在crates.io),这将允许您以原始模式阅读。 Github 存储库中有一些示例说明了如何执行此操作。

    【讨论】:

    • 没有一个例子使用非阻塞标准输入
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-12
    • 2018-07-26
    • 1970-01-01
    • 2011-12-27
    • 2010-11-19
    相关资源
    最近更新 更多