rust 如何从标准输入中读取非阻塞数据?

vohkndzv  于 2023-02-04  发布在  其他
关注(0)|答案(3)|浏览(507)

有没有办法检查Rust中stdin上的数据是否可用,或者执行一个读取操作,立即返回当前可用的数据?
我的目标是能够读取由shell中的光标键产生的输入,shell被设置为立即返回所有读取的数据。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 :(
92dk7w1h

92dk7w1h1#

将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);
}
sd2nnvve

sd2nnvve2#

大多数操作系统默认以阻塞的方式使用标准输入和输出,难怪Rust库会取而代之。
要以非阻塞的方式读取阻塞流,您可以创建一个单独的线程,这样额外的线程会阻塞而不是主线程。检查阻塞文件描述符是否产生了一些输入是类似的:生成一个线程,让它读取数据,检查到目前为止它是否产生了任何数据。
Here's是我使用的一段代码,目的类似于交互式处理管道输出,希望可以作为一个示例,它通过channel发送数据,channel支持try_recv方法,允许您检查数据是否可用。
Someone has told memio可能用于以非阻塞方式从管道中读取数据,因此您可能也想检查一下它。我认为将stdin文件描述符(0)传递给Receiver::from_raw_fd应该可以正常工作。

mv1qrgav

mv1qrgav3#

你也可以考虑使用ncurses(也在crates.io上),它允许你在raw模式下读取,Github库中有一些例子展示了如何做到这一点。

相关问题