在上一篇程序示例3中,实际上是存在错误的,如在下图中,父进程不仅接收了子进程发送来的数据,有时候也接收了它自己发送的数据。
匿名管道中一般不会相互发送数据,而是只有一个流向。
要么父进程往管道中写,子进程从管道中读(上图中1);(此时,可关闭父进程的读端,子进程的写端,因为它们不会被用到)
要么子进程往管道中写,父进程从管道中读(上图中2)。(此时,可关闭子进程的读端,父进程的写端,因为它们不会被用到)
#include <stdio.h>
#include <unistd.h>
#include <string.h>
//子进程发送数据给父进程,父进程读取到数据后输出
int main()
{
//在fork之前创建管道
int pipefd[2];
int ret = pipe(pipefd);
if (ret == -1)
{
perror("pipe");
return -1;
}
//创建子进程
pid_t pid = fork();
if (pid > 0)
{
printf("parent process,pid=%d\n", getpid());
//关闭写端
close(pipefd[1]);
//父进程 从管道的读取端读取数据
char buf[1024] = {0};
while (1)
{
//读取数据
int len = read(pipefd[0], buf, sizeof(buf));
printf("parent recv :%s,pid=%d\n", buf, getpid());
bzero(buf,1024);
//写入数据
//char* str="hello,I am parent";
//write(pipefd[1],str,strlen(str));
sleep(1);
}
}
else if (pid == 0)
{
//子进程
printf("child process,pid=%d\n", getpid());
//关闭读端
close(pipefd[0]);
//char buf[1024]={0};
while (1)
{ //向管道的写入端写入数据
char *str = "hello,I am child";
write(pipefd[1], str, strlen(str));
sleep(1);
//读取数据
//read(pipefd[0],buf,sizeof(buf));
//printf("child recv :%s,pid=%d\n", buf, getpid());
//bzero(buf,1024);
}
}
return 0;
}
案例:实现 ps aux | grep xxx
程序:
/*
实现 ps aux | grep xxx 父子进程间通信
子进程:ps aux ,子进程将数据发送给父进程
父进程:获取到数据,过滤(过滤暂未实现)
pipe()创建管道
execlp()执行ps命令
子进程将标准输出 stdout_fileno 重定向到管道的写端 dup2()
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
//创建一个管道
int fd[2];
int ret=pipe(fd);
if(ret==-1)
{
perror("pipe");
return -1;
}
//创建子进程
pid_t pid=fork();
char buf[1024]={0};
if(pid>0)
{
//父进程
//关闭写端
close(fd[1]);
//读取数据
int len=-1;
while((len=read(fd[0],buf,sizeof(buf)))>0)
{
//过滤并输出(这里过滤没有实现)
printf("%s",buf);
memset(buf,0,1024);
}
}
else if(pid==0)
{
//子进程
//关闭读端
close(fd[0]);
//文件描述符的重定向 STDOUT_FILENO-》fd[1]
dup2(fd[1],STDOUT_FILENO);
//执行ps aux
execlp("ps","ps","aux",NULL);
perror("execlp");//execlp函数执行失败了,这里往下的语句才会执行
return -1;
}
else
{
perror("fork");
return -1;
}
return 0;
}
参考:《Linux高并发服务器开发》2.13匿名管道通信案例