如何从stdin读取非阻塞?

问题描述 投票:5回答:3

有没有办法检查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 :(
rust
3个回答
3
投票

大多数操作系统默认以阻塞方式使用标准输入和输出。难怪Rust工具库紧随其后。

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

Here's我使用的一段代码,其目的是以交互方式处理管道输出,并且可以作为一个例子。它通过channel发送数据,try_recv支持Someone has told me方法 - 允许您检查数据是否可用。

mio可能会使用PipeReader::from_fd以非阻塞的方式从管道中读取数据,因此您可能也想查看它。我怀疑将stdin文件描述符(0)传递给channel应该可行。


2
投票

将OP的评论转换为答案:

您可以生成一个线程并通过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); } 在主线程中轮询该通道。

ncurses

1
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.