我们在编程中常常遇到这样的问题:就是父进程需要截获子进程的输出,进行数据分析或者作为数据返回给socket
通信中的另一端!如何来解决这样的问题呢?
这里就用到了进程之间的管道通信和dup2函数!
在介绍dup2函数之前我们先来了解一下!我们先来了解一下什么是管道!
管道是UNIX系统IPC的最古老的方式,并且所有的UNIX和LINUX系统都提供了这样通信方式!
管道是由pipe函数所创建的:
#include
int pipe(int fd[2]);
在这里传递的参数fd[2],实际上是两个文件描述符,其中fd[0]为读而打开的文件描述符,fd[1]为写打开的文件
描述符!当我们在父进程中声明了一个这样的管道,然后执行fork()函数创建出一个子进程时,子进程中就保留了
一个fd[2]的副本,这样我们在子进程中关闭fd[0],在父进程中关闭fd[1],这样就建立一个在父进程和子进程之间
通信的通道,这样从子进程写入信息,就可以从父进程读出来!就如同在父进程和子进程之间建立了一个信息的
通道,我们称之为管道!
熟悉了管道的概念之后,假如我们想要截获子进程的输出,只需要将子进程的标准输出复制给fd[1],这样我们就
可以从父进程中截获子进程的输出了,从而便于我们进行下一步的数据分析,这个复制操作就用到了我们这里提到
的dup2函数!
int dup2(int oldfd,int fd);
dup2
函数跟dup函数相似,但dup2函数允许调用者规定一个有效描述符和目标描述符的id。dup2函数成功返回时,目标描述符(dup2函数的第二个参
数)将变成源描述符(dup2函数的第一个参数)的复制品,换句话说,两个文件描述符现在都指向同一个文件,并且是函数第一个参数指向的文件。
下面来看一个实际的例子:
#include"apue.h"
#include
#include"error.c"
#include
void pr_exit(int status)
{
if(WIFEXITED(status))
{
printf("normal termination, exit status = %d\n",WEXITSTATUS(status));
}
else if(WIFSIGNALED(status))
{
printf("abnormal termination, signal number = %d%s\n", WTERMSIG(status),
#ifdef WCOREDUMP
WCOREDUMP(status) ? "(core file generated)" : "");
#else
"");
#endif
}
else if(WIFSTOPPED(status))
{
printf("child stopped, signal number = %d\n", WSTOPSIG(status));
}
}
int main(void)
{
pid_t pid;
int status;
int fd[2];
int n;
char line[MAXLINE];
int s = open("ddx",O_RDWR);
if(pipe(fd) < 0)
{
err_sys("pipe error!");
exit(0);
}
if((pid = fork()) < 0)
{
err_sys("fork error!");
}
else if(pid == 0)
{
close(fd[0]);
dup2(fd[1],STDOUT_FILENO);//z将标准输出指向了fd[1]!
if(execl("/home/mini/scripts/sh09.sh","hello","hello",(char*)0) < 0)
{
err_sys("execl error!");
}
}
else
{
close(fd[1]);
n = read(fd[0],line,MAXLINE);
if(write(s,line,n) < 0)//读取标准输出写入文件!!
{
perror("error:");
}
close(s);
}
if(waitpid(pid,&status,0) < 0)
{
err_sys("waitpid error!");
}
pr_exit(status);
exit(0);
}
本例中我们在父进程中fork()出来一个子进程,并且在子进程中,调用了execl函数执行了一段shell程序,
利用管道和dup2函数截获了子进程的输出,返回给父进程之后,由父进程写入文件!!在这里简单的描述了一下
dup2和管道的用法,以供参考!!
阅读(3653) | 评论(0) | 转发(1) |