如何让子进程使用另一个终端输入和输出?

时间:2015-10-15 17:45:02

标签: c fork stdout stdin

我搜索了很多,但没有找到满足我需求的真正解决方案。

我需要forked子进程使用另一个终端的 stdin stdout ,而不是在这里调用它的一个例子,我想做什么

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

int main()
{
    pid_t pid;
    printf("process parent pid is %d\n",getpid());
    pid =fork();
    printf("process child pid is %d\n",pid);
    if(pid==0)
    {
        //int exit_status = system("gnome-terminal");
        char a[20];
        while(1)
        {
            scanf(" %s",a);
            printf("child %s \n",a);
        }
    }
    while(1)
    {
        char b[20];
        scanf(" %s",b);
        printf("parent  %s \n",b);
    }
}

我需要孩子例如通过另一个终端与用户互动。

2 个答案:

答案 0 :(得分:2)

正如我理解你的问题,你希望fork一个子进程,它通过一个虚拟终端,即gnome-terminal与用户进行所有的交互。 然后,首先,阅读有关终端和炮弹之间差异的this article。然后阅读有关Unix伪终端的this article。然后read this one关于/ dev / pts文件系统。这将为您提供我的答案背景。

这是创建连接到不同终端(虚拟终端)的子进程的一种方法。我承认,我很久没有这样做了,然后是物理TTY,而不是伪终端。但是背景信息应该可以帮助您解决可能遇到的任何问题。

整体方法是分叉两个子进程。一个用于虚拟终端,一个用于工作进程。然后,您将执行虚拟终端进程,使其在shell退出时不会关闭。你真的甚至不希望它为这个问题启动shell或任何程序,因为你将提供将与之交互的运行进程。使用gnome-terminal,在进程退出后不太容易告诉它挂起。您应该read this获取有关如何保留它的建议。另一种方法是使用“xterm”,它具有“--hold”选项,似乎适合于此目的。 “xterm”也有“-S”选项,听起来就像你需要的那样。要使用“-S”选项,您需要阅读PTS

由于XTERM有你需要的选项,我将描述基于XTERM而不是gnome-terminal的方法。

在您的子程序中,您需要打开/ dev / ptmx以获取主伪终端文件描述符。然后在FD上调用ptsname()以获取PTS的名称。您需要该名称来通知XTERM要使用哪个从属PTS。您必须通过在主FD上调用grantpt()和unlockpt()来授予访问权限并解锁FD。接下来,使用-S选项分叉另一个进程和exec()XTERM,它以“-S / dev / pts / 123/42”或等效“-S123 / 42”的形式获取PTS名称和文件描述符号。在这种情况下,我认为你不需要“ - ”,但如果事实证明你这样做,就加上它。 (有关使用-S的更多信息,请参阅XTERM手册页)

这将终端设置为子进程的主pseuo-terminal文件描述符上的用户I / O设备。所以,接下来你将文件描述符复制到fd 0和fd 1(如果你想让stderr去那里那么fd 2)。

对不起,这太笼统了。该方法应该可行,但您可能需要根据您的特定Linux / Unix风格进行调整。请让我知道你是怎么做的,如果我有机会,我会得到一个Linux并自己尝试一下。

答案 1 :(得分:0)

stdin是文件描述符0.要附加到另一个文件或流(或设备),您的子进程必须先关闭文件描述符0,然后再打开另一个文件(设备)。打开将返回fd 0(如果成功),因为它现在是第一个可用的。您可以使用dup()以原子方式执行此操作。

您需要获得打开设备的权限。

例如,假设您感兴趣的输入设备是/ dev / input / tty1 ...

if(childpid == 0)
{
    int fd = open("/dev/input/tty1", open_args);
    if(fd >= 0)
    {
        /* Close stdin, duplicate the fd just opened to stdin */
        dup2(0, fd);
        // etc...