unix pipe() 和dup2()的使用方法和原理
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了unix pipe() 和dup2()的使用方法和原理相关的知识,希望对你有一定的参考价值。
在父子进程通信以及redirection中,经常用pipe(),close()以及dup2()函数来实现。向各位请教,两者的使用方法和原理。谢谢大家。
...可以更清楚地解释一下原理么?
close(),用于关闭清空pipe某端,参数为表示pipe端口数组二元素之一。
dup2(),用于redirection, 将pipe某端与标准i/o相连,即将standout information 写入或者pipe内容被standin独出。如dup2(data[1], STDOUT_FINENO).是进程与外界相连的一个工具。本回答被提问者采纳 参考技术B 1. 编写程序w.c随机产生1000个的整数,把他们写到屏幕上,每行一个。
2. 编写程序r.c从键盘读入整数计算它们的平均数,遇到文件结束符^D终止。
3. 合并程序w.c和r.c为wr.c用fork产生两个进程,子进程为完成w.c的工作,父进程完成r.c的工作,使得父进程产生的整数通过pipe传递到子进程。
五、实验报告要求
给出wr.c的程序源代码。
六、参考实例
wr.c:
#include <stdio.h>
main()
int i,pid,r,x,count,p[2];
long int sum;
if(pipe(p)==-1)printf("pipeerr\n");exit(1);
if((pid=fork())==-1)printf("forkerr\n");exit(1);
if(pid==0)
close(p[0]);
dup2(p[1],1);
srand(getpid());
for(i=0;i<1000;i++)printf("%d\n",rand());
exit(0);
count=0;sum=0;
if(p<=0)printf("error open\n");exit(0);
close(p[1]);
dup2(p[0],0);
while(1)
x=0;
r=scanf("%d",&x);
if(r<=0)break;
count++;
sum+=x;
printf ("avg=%lf\n", (0.0+sum)/count);
wait(&x);
使用 stdout/stderr 以外的管道与子进程通信
【中文标题】使用 stdout/stderr 以外的管道与子进程通信【英文标题】:Communicate with a subprocess using pipes on other than stdout/stderr 【发布时间】:2015-02-13 17:46:43 【问题描述】:这就是我 fork/exec 一个子进程并与之通信的方式(伪代码):
int cout_pipe[2];
pipe(cout_pipe);
fork();
if (child)
dup2(cout_pipe[1],STDOUT_FILENO);
execv();
if (parent)
File* cout_file = fdopen(cout_pipe[0], "r");
我的问题是:
我真的不想读取子进程的标准输出,我希望子进程在标准输出以外的文件描述符上写入。而且,我希望从该文件描述符中读取上述代码。
子进程用python写,主进程用C++写。
我想我可以改变那行,从:
dup2(cout_pipe[1],STDOUT_FILENO);
到
dup2(cout_pipe[1],MY_OWN_RANDOM_FD_NUMBER);
并以我写入 MY_OWN_RANDOM_FD_NUMBER 而不是标准输出的方式对子进程进行编码。
这是一个好的解决方案吗?可行吗?我怎样才能找出一个好的 MY_OWN_RANDOM_FD_NUMBER?有更好的选择吗?
【问题讨论】:
【参考方案1】:除非您需要特定的 fd,例如标准输出,否则 dup2
没有任何意义。只需将cout_pipe[1]
转换为字符串,并将其作为命令行参数传递给子进程(在exec
中)。在 Python 端,从sys.argv
中提取参数,将其转换回int
,然后使用os.fdopen
为其获取file
。
【讨论】:
将 cout_pipe[1] 转换为字符串?所以这意味着 pipe(cout_pipe) 使 cout_pipe[1] 成为有效的 fd?。还有什么是转换 itoa(cout_pipe[1]) 的最佳方式? @Kampipe( cout_pipe )
将管道的两个 fd 放入 cout_pipe
。您可能想要使用dup2
的唯一原因是您对 fd 的数值不满意。至于转换,任何标准解决方案都可以解决问题;如果您在子端执行此操作,就在exec
之前,并且您的系统有itoa
(它不是标准的),那么即使这样也是可以接受的;如果您使用的是 C++11,则可以使用 std::to_string
——只需确保在调用 .c_str()
之前将结果保存到具有足够生命周期的变量中即可。【参考方案2】:
在您描述的情况下,无需复制文件描述符。对 pipe() 的调用已经在 cout_pipe 数组中创建了您需要的文件描述符。
通常,子进程在执行之前简单地关闭管道的读取端,而父进程关闭管道的写入端。子进程将它想要的任何内容写入写入端,父进程读取或以其他方式监视管道的读取端。
如果您的问题是“子进程如何知道它执行后的 fd 编号,那么我会说当您在子进程中调用 execv() 时将其作为执行参数传递。”
类似:
int child_pipe[2];
FILE *child_file;
void forkchild(void)
int ret;
char child_pipe_fd_str[16];
pipe(child_pipe); /* TODO: check return value! */
if (0 == (ret = fork())) /* child */
close(child_pipe[0]);
sprintf(child_pipe_fd_str, "%d", child_pipe[1]);
execv(my_python_script, child_pipe_fd_str, NULL);
else if (-1 != ret) /* parent */
close(cout_pipe[1]);
child_file = fdopen(cout_pipe[0], "r");
else
perror("Fork failed!");
abort();
【讨论】:
在上述情况下,当child写入stdout时,stdout之前被重定向到pipe,因此父进程只需从pipe读取即可读取child的stdout。我希望孩子不要写入标准输出,而是写入另一个文件,并且父进程可以读取它。 如果你想将管道的写入端包装在一个文件中,然后在你执行之后在你的子进程中调用 fdopen(write_side, "w")。诀窍是知道您执行的子 AFTER 中管道写入端的文件描述符#。一种方法是在调用 execv() 时将其作为执行参数显式传递。清楚吗? 好的,所以我应该在 fork 之后,exec 之前创建一个 FILE,然后 dup2(cout_pipe[1],this_files_fd),然后将 FILE 的 fd 作为 exec 的参数传递给子进程,并在 python 中我给这个 fd 写信? 不,您应该使用 os.fdopen 在您的新 Python 进程中创建您执行的文件结构 AFTER。诀窍是知道你需要打开什么fd#。您应该将其作为执行参数传递给子 C 进程中的 execv() 。我会在我的答案中发布一些代码。以上是关于unix pipe() 和dup2()的使用方法和原理的主要内容,如果未能解决你的问题,请参考以下文章
UNIX环境高级编程APUE练习3.2-不用fcntl实现dup2的功能