在 child 调用 exec() 之后使用 pipe()

Using pipe() after child calls exec()

我的最终目标是让 parent 进程将文本行传递给 child,然后 child 进程会将文本打印到标准输出。 child 在后台发送到 运行 "permanently",而 parent 获取用户输入并将其传递给 child。我更喜欢单独程序中的 child。通过 if 语句区分 child 和 paretn 就像软糖一样混乱。

我正在研究管道,但我不确定在 child 调用 exec() 到另一个程序后管道是否有可能在 parent/child 之间进行通信。

这可能吗?如果是这样,你有什么例子可以指给我看吗?如果没有,那我可以使用什么IPC方法?

标准方案是让程序作为 child 与管道无关,只使用 stdin / stdout。您可以通过 dup2() 将管道的相应末端设置为 fd 01(或同时使用两个管道进行双向通信)来实现此目的,对应于 STDIN_FILENOSTDOUT_FILENO。之后,执行你的 child 程序。

当然,还有其他选择,例如"named pipes" 如果您需要 stdin / stdout 用于 child.

中的不同目的

如果您自己编写这两个部分,您可能需要考虑更简单的解决方案:

Differentiating between child and parent through if statements is messy as fudge.

无论如何你都必须这样做,至少是为了连接管道和调用 exec()。只需创建单独的代码文件并根据需要调用 parent_main()child_main() 之类的东西(随便你怎么称呼它们)。

执行 exec*() 函数后,child 共享 parent 进程的所有文件描述符。因此,如果您在 fork() 之前创建一个管道,您就可以在这两个管道中访问 read/write fd。

通常的方法是:

  • 创建管道(一个读fd,一个写fd)
  • fork()
  • 在parent中:
    • close read fd(你不会在这里阅读parent)
    • 将数据写入write fd
    • wait/die
  • 在child中:
    • close write fd(你不会写from child)
    • 从read fd读取数据
    • wait/die

不明白你为什么要执行一个新进程。如果确实需要,您必须使用标准 stdin/stdout (请参阅其他答案)或有一个程序可以接受 fd (文件描述符,一个整数)作为参数,以便知道哪个是管道。我觉得不太好。

实际上,使用 popen 自动管理通信渠道

更容易做到这一点

FILE *popen(const char *command, const char *mode); The popen() function shall execute the command specified by the string command. It shall create a pipe between the calling program and the executed command, and shall return a pointer to a stream that can be used to either read from or write to the pipe.

The environment of the executed command shall be as if a child process were created within the popen() call using the fork() function, and the child invoked the sh utility using the call:

execl(shell path, "sh", "-c", command, (char *)0);

where shell path is an unspecified pathname for the sh utility.

The popen() function shall ensure that any streams from previous popen() calls that remain open in the parent process are closed in the new child process.

The mode argument to popen() is a string that specifies I/O mode:

If mode is r, when the child process is started, its file descriptor STDOUT_FILENO shall be the writable end of the pipe, and the file descriptor fileno(stream) in the calling process, where stream is the stream pointer returned by popen(), shall be the readable end of the pipe.

If mode is w, when the child process is started its file descriptor STDIN_FILENO shall be the readable end of the pipe, and the file descriptor fileno(stream) in the calling process, where stream is the stream pointer returned by popen(), shall be the writable end of the pipe.

If mode is any other value, the result is undefined.

After popen(), both the parent and the child process shall be capable of executing independently before either terminates.

Pipe streams are byte-oriented.

RETURN VALUE

Upon successful completion, popen() shall return a pointer to an open stream that can be used to read or write to the pipe. Otherwise, it shall return a null pointer and may set errno to indicate the error.

例如,假设您要将 Hello world 发送到 child:

#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
int main()
{
  FILE* toChild;
  toChild = popen("./child", "w");//child is executable of the other file: change the name
  int res = fputs( "Hello World\n", toChild);
  pclose(toChild);
  return 0;
}

和 child:

int main()
{
  char p[100];
  int n;
  do{
    n = scanf("%s", p);
    if (n>0) {
    printf("INPUT MESSAGE: \"%s\n\"", p);
    //free(p);
    }
    else {
      printf( "%d, No matching characters\n", n);
    }
  }while(n>0);
  return 0;
}

如果您使用的是纯 POSIX 系统(而不是 OSX),您还可以将 scanf("%ms", &p)char* p 一起使用,然后再使用 free(p)。 =20=]