如何在同时传送stdio的同时模拟TTY?

问题描述

我正在寻找一种跨平台的解决方案,用于在Rust中模拟TTY(PTY?),同时还要传递stdio

前端基于显示交互式终端的Web技术。用户可以运行命令,所有输入都将发送到Rust后端,在该后端执行命令。 Std {in,out,err}会向后发送,以提供交互式体验。

这是一个简化的示例(仅通过管道输出stdout):

let mut child = Command::new(command)
    .stdout(Stdio::piped())
    .spawn()
    .expect("Command Failed to start");

loop {
    let read = reader.read(&mut chunk);

    if let Ok(len) = read {
        if len == 0 {
            break;
        }
        let chunk = &chunk[..len];

        send_chunk(chunk); // send chunk to frontend
    } else {
        eprintln!("Err: {}",read.unwrap_err());
    }
}

当前,运行命令tty打印:not a tty,但是理想情况下,它应该输出文件名(例如/dev/ttys002)。并且诸如atty之类的程序应返回true

仅在终端中运行stdio继承的作品的后端,但随后我无法将stdio发送回前端。

解决方法

定义“跨平台”。就PTY而言,这些是内核支持的伪设备,包括ioctl和所有内容。实际上,终端仿真器将要做的很多事情就是实现这些ioctl的接收端。

只要您使用的是具有BSD API(包括Linux)的计算机,最佳的操作方法就是openpty并随之滚动。如果要移植到不支持BSD PTY的系统,则必须在子进程中挂接tty函数(通过预加载帮助程序库)。