我一直有麻烦的简洁地描述我想要完成的,但我试图做的是写一个程序,将执行其他程序/脚本作为插件,并在执行期间,促进我的程序和其他程序/脚本之间的各种请求(如请求用户列表,例如)的通信。但是,如果这些其他程序/脚本需要与最终用户进行通信,我也不希望妨碍这一点。我探索了一些其他方法(如dbus, http api,不同的文件句柄等),所有这些选项对于我想要做的事情来说都是太重的解决方案,或者我在实现方面没有取得多大成功(就像最后一个想法的情况一样),而只是使用正常的STDIN/STDOUT似乎是最干净的路径。
这是我目前的资料:
let mut child = Command::new("test.pl")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.expect("Failed to spawn child process");
let mut stdin = child.stdin.as_mut().unwrap();
writeln!(&mut stdin, "Hey, testing!").unwrap();
let stdout = child.stdout.as_mut().unwrap();
let stdout_reader = BufReader::new(stdout);
let stdout_lines = stdout_reader.lines();
for line in stdout_lines {
match line.unwrap().as_str() {
"member_list" => {
println!("Here's a member list");
let mlist = cluster::members_list()?;
for (member, port) in mlist.iter() {
writeln!(&mut stdin, "{}:{}", member, port);
}
}
e => {
println!("{}", e);
}
};
}
child.wait().unwrap();
这在我的程序和另一个程序之间的通信中工作得很好,如果它与通信所需的任何关键字不匹配,则将STDOUT传递给用户。但是,我想不出一种能够将信息传递给其他程序的STDIN而不妨碍其他程序向用户请求输入的方法(例如,如果程序需要向用户而不是我的程序请求输入)。我尝试了drop(stdin);
的一个愚蠢的用法,后来重新声明了stdin,当然,由于作用域问题,这不起作用。
我真的试图避免充当STDIN的中介,因为这似乎会非常混乱。如果你能告诉我如何才能做到这一点,我将不胜感激。除了通过STDIN/STDOUT之外,我也对促进这种交流的其他想法持开放态度。
谢谢!
您可以使用匿名管道。在Linux中,在较高的级别上,它看起来像这样:
-
您的进程使用
pipe
系统调用创建管道,该系统调用返回一对fd,一个用于管道的读端,另一个用于管道的写端 -
你的进程然后分叉。在子进程中,然后调用
exec
来启动您想要运行的进程,将其中一个fd作为命令行参数传递给它 -
新程序获取FD并使用它与父进程通信。
-
父进程和子进程都应该注意关闭代表它们未使用的连接的一半的fd。
您可以在rust中这样做——所需的系统调用在libc crate中公开,或者通过对rust更友好的nix crate公开。
我还偶然发现了interprocess
crate,它提供了对这些低级调用的抽象。
这些新创建的fd完全独立于进程的stdin/stdout/stderr。
如果需要双向通信,您可以使用两个这样的管道(每个方向一个)-但是在这种情况下,使用匿名套接字可能更容易,使用socketpair
系统调用创建。这与管道的工作方式类似,返回一对fd -除了在这种情况下fd是双向的。同样,libc
和nix
公开了这个系统调用。