我编写并维护了一个程序rlwrap,该程序使用伪终端与子进程进行通信。 Pseudo-terminals(ptys)在所有类似Unix(-like)的系统中都可以找到,但是它们在不同平台上的行为略有不同。

例子:在rlwrap中,父进程保持从属pty打开,以保持子级终端设置上的标签(例如,在Linux和FreeBSD上,可以使用主控,但在Solaris中则不能使用主控)。

在FreeBSD(8.2)(而不是Linux)上,这会导致 child 的最终输出丢失。例如:

#include <stdio.h>

/* save as test.c and compile with gcc -o test test.c -lutil */

#define BUFSIZE 255

int main(void) {
  int master, slave;
  char buf[BUFSIZE];
  int nread;

  openpty(&master, &slave, NULL, NULL, NULL);

  if (fork()) {       /* parent:                                                      */
    close(slave);     /* leave this out and lose slave's final words ... WHY?         */
    do {
      nread = read(master, buf, BUFSIZE);
      write(STDOUT_FILENO, buf, nread); /* echo child's output to stdout              */
    } while (nread > 0);
  } else {             /* child:                                                      */
    login_tty(slave);  /* this makes child a session leader and slave a controlling   */
                       /* terminal for it, then dup()s std{in,out,err} to slave       */
    printf("Feeling OK :-)\n");
    sleep(1);
    printf("Feeling unwell ... Arghhh!\n"); /* this line may get lost                 */
  }
  return 0;
}

父进程将按预期方式回显子级的输出,但是当我省略close(slave)(使其像rlwrap一样保持打开状态)时:

FreeBSD上的
  • ,父级看不到最终输出行,而是读取EOF。 (如果有的话,我会想到相反的结果-保持从属端打开将防止输出丢失)
  • 另一方面,在Linux上,甚至在 child 死后(无论我们是否关闭从站),也从未看到过EOF。

    此行为记录在某处吗?有理由吗?我可以在不关闭父进程的情况下绕过它吗?

    我发现不将从属设备作为控制终端-用一些简单的login_tty调用替换dup()调用-将解决此问题。但是,这不是rlwrap的解决方案:相当多的命令需要控制终端(/dev/tty)进行通信,因此rlwrap必须为其提供一个。

    最佳答案

    我认为Pty有独特的独立行为。

  • 如果写入了最后一个数据,系统将终止
  • 如果 child 退出(管道断开?),系统终止

    该代码依赖于存在时间足够长的管道来发送数据,但是退出子进程可能会导致虚拟通道在接收到数据之前被删除。

    这对于Pty而言将是唯一的,而对于真正的终端机则不存在。

    关于c - 如果未在父级上关闭,则从属pty的最终输出将丢失。为什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23458160/

  • 10-11 18:57