Linux 管道作为输入和输出

发布于 2024-08-10 19:57:35 字数 282 浏览 1 评论 0原文

我想在 Linux 操作系统上的 C 程序中执行以下操作:

  • 使用系统调用(或 2)创建 PIPE
  • 使用 exec() 执行新进程
  • 将进程的 STDIN 连接到先前创建的管道。
  • 将进程的输出连接到另一个 PIPE。

这个想法是为了性能目的而绕过任何驱动器访问。

我知道使用 PIPE 系统调用创建管道非常简单 我可以使用 popen 创建一个用于输入或输出目的的管道。

但是您将如何对输入和输出执行此操作呢?

I would like to do the following inside a C program on a Linux os:

  • Create a PIPE using a syscall (or 2)
  • Execute a new process using exec()
  • Connect the process's STDIN to to the previously created pipe.
  • Connect the process's output to another PIPE.

The idea is to circumvent any drive access for performance purposes.

I know that the creation of pipes is quite simple using the PIPE system call
and that I could just use popen for creating a pipe for input OR output purposes.

But how would you go about doing this for both input and output?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

み青杉依旧 2024-08-17 19:57:35

您需要非常小心地处理管道:

  1. 调用 pipeline() 两次,一次用于管道到子级,一次用于管道从子级,产生 4 个文件描述符。
  2. 调用 fork()。
  3. 儿童时期:
    • 在标准输入(文件描述符 0)上调用 close()。
    • 调用 dup() - 或 dup2() - 将管道到子级的读取结尾转换为标准输入。
    • 在管道到子级的读取端调用 close()。
    • 在管道到子级的写入结束时调用 close()。
    • 在标准输出(文件描述符 1)上调用 close()。
    • 调用 dup() - 或 dup2() - 将 pipeline-from-child 的写入结尾写入标准输出
    • 在 Pipe-from-child 的写入结束时调用 close()。
    • 在 Pipe-from-child 的读取端调用 close()。
    • 执行所需的程序。
  4. 在父级中:
    • 在管道到子级的读取端调用 close。
    • 在 Pipe-from-child 的写入端调用 close。
    • 循环在管道到子级的写入端将数据发送到子级,并在管道从子级的读取端从子级读取数据
    • 当不再需要发送给子级时,关闭管道到子级的写入端。
    • 收到所有数据后,关闭 pipeline-from-child 的读取端。

注意有多少个闭合,尤其是在孩子身上。如果使用 dup2(),则不必显式关闭标准输入和输出;但是,如果您执行显式关闭,则 dup() 可以正常工作。另请注意,dup() 和 dup2() 都不会关闭重复的文件描述符。如果您忽略关闭管道,则两个程序都无法正确检测 EOF;当前进程仍然可以写入管道的事实意味着管道上没有 EOF,并且程序将无限期挂起。

请注意,此解决方案不会改变子级的标准错误;它会到达与父级的标准错误相同的位置。通常,这是正确的。如果您有特定要求以不同方式处理来自子级的错误消息,则也对子级的标准错误采取适当的操作。

You need to be quite careful with the plumbing:

  1. Call pipe() twice, one for pipe-to-child, one for pipe-from-child, yielding 4 file descriptors.
  2. Call fork().
  3. In child:
    • Call close() on standard input (file descriptor 0).
    • Call dup() - or dup2() - to make read end of pipe-to-child into standard input.
    • Call close() on read end of pipe-to-child.
    • Call close() on write end of pipe-to-child.
    • Call close() on standard output (file descriptor 1).
    • Call dup() - or dup2() - to make write end of pipe-from-child into standard output
    • Call close() on write end of pipe-from-child.
    • Call close() on read end of pipe-from-child.
    • Execute the required program.
  4. In parent:
    • Call close on read end of pipe-to-child.
    • Call close on write end of pipe-from-child.
    • Loop sending data to child on write end of pipe-to child and reading data from child on read end of pipe-from-child
    • When no more to send to child, close write end of pipe-to-child.
    • When all data received, close read end of pipe-from-child.

Note how many closes there are, especially in the child. If you use dup2(), you don't have to close standard input and output explicitly; however, dup() works correctly if you do the explicit closes. Also note that neither dup() nor dup2() closes the file descriptor that is duplicated. If you omit closing the pipes, then neither program can detect EOF correctly; the fact that the current process can still write to a pipe means that there is no EOF on the pipe, and the program will hang indefinitely.

Note that this solution does not alter standard error for the child; it goes to the same place as standard error for the parent. Often, this is correct. If you have a specific requirement that error messages from the child are handled differently, then take appropriate action on the child's standard error too.

漆黑的白昼 2024-08-17 19:57:35

根据您的需要,您可能会发现使用 mkfifo(1) 来创建命名管道并使进程读/写该文件更容易。虽然文件在文件系统中命名,但使用匿名管道的开销不应太大。

Depending on your needs, you may find it easier just to use mkfifo(1) to make a named pipe and have your processes read/write to that file. While the file is named in the filesystem, the overhead of using an anonymous pipe shouldn't be appreciable.

浅紫色的梦幻 2024-08-17 19:57:35

最简单的方法可能是执行 /bin/sh,这样您就可以使用熟悉的 shell 语法来指定管道并减轻所有复杂性。

像这样的东西:

execlp("sh", "-c", "cat /dev/zero | cat > /dev/null", NULL);

The easiest way is probably executing /bin/sh, this way you can use familiar shell syntax for specifying pipes and offload all complexities.

Something like:

execlp("sh", "-c", "cat /dev/zero | cat > /dev/null", NULL);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文