管道

PIPE:半双工通信(无名管道),数据在一个方向上流动(父子进程间通信)。常用在终端敲入一个命令,让shell执行则创建一个进程,通道将敲入的前一个命令的标准输出连接到后一条命令的标准输入。

  Int pipe(int fd[2]);//创建管道. fd[0]是读管道文件描述符,fd[1]是写管道文件描述符。

 半双工管道的方法:

1、在单进程中,管道两端相互连接。

2、在单进程中,管道fd[1]数据经过内核,fd[0]从内核输出.

3、在父子进程中,父进程先pipe,fork(如图1),然后数据从父进程fd[0]进,从子进程fd[1](如图2)。(该方式关闭父的fd[1],子的fd[0]

4、利用方法3的将管道文件描述符复制到标准输入或标准输出.子进程执行另一个程序(该程序从标准输入、输出中读、写).    

5、利用管道实现父子进程之间的同步。(编写TELL_WAIT, TELL_PARENT, TELL_CHILD等等)

6、利用管道实现的标准I/O  popen,pclose函数及用popen实现过滤器功能.

7、协调进程.

     方法3表述如图1,2:

                            

                

        

        :

A:在3方法中 read和write需注意:

a. read一个关闭写端的管道,数据全部read后,返回0.表示文件结束(若写端还有进程(这里指的是写进程吗???),则不会文件结束)

b. Write一个关闭读端的管道,将会产生SIGPIPE信号,忽略或从捕捉函数中返回,write返回-1,error是EPIPE.

             B:  PIPE_BUF 规定了内核缓冲区的大小,在多进程同时对同一个管道write,并且数据超过PIPE_BUF各进程所写数据会产生交

.pathconffpathconf函数可以确定PIPE_BUF.

               

方法4表述应用:将文件复制到分页程序通过管道将输出直接送到分页程序

   #include "apue.h"

   #include <sys/wait.h>

   #define DEF_PAGER "/bin/more" /* default pager program */

 

     int  main(int argc, char *argv[])

    {

int n;

int fd[2];

pid_t pid;
char *pager, *argv0;
char line[MAXLINE];

FILE *fp;

 

if (argc != 2)   err_quit("usage: a.out <pathname>");

if ((fp = fopen(argv[1], "r")) == NULL)   err_sys("can't open %s", argv[1]);

if (pipe(fd) < 0)    err_sys("pipe error"); //创建管道

 

if ((pid = fork()) < 0) {    err_sys("fork error");} //创建进程

else if (pid > 0)

 {//父进程

 close(fd[0]); /* close read end */

while (fgets(line, MAXLINE, fp) != NULL) /* parent copies argv[1] to pipe */

{

n = strlen(line);

if (write(fd[1], line, n) != n)   err_sys("write error to pipe"); //从命令行文件中readwritePIPE.

}


if (ferror(fp))  err_sys("fgets error");

close(fd[1]); /* close write end of pipe for reader */

if (waitpid(pid, NULL, 0) < 0)   err_sys("waitpid error");//等待子进程退出.

exit(0);

}

else

{ //子进程

close(fd[1]); /* close write end */

if (fd[0] != STDIN_FILENO)//判断是否等于标准输入

{    //这里dup2前要先判断,避免fd[0]的副本STDIN_FILENO在调用close(fd[0])时被关闭.

if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) err_sys("dup2 error to stdin");//fd[0]复制给标准输入.(此后标准输入的数据会到PIPE的读端)

close(fd[0]); /* don't need this after dup2 */

}

 

if ((pager = getenv("PAGER")) == NULL)   pager = DEF_PAGER;  /*从环境变量中或者直接赋值get分页程序*/

if ((argv0 = strrchr(pager, '/')) != NULL)  argv0++; /* step past rightmost slash */

else   argv0 = pager; /* no slash in pager */

 

if (execl(pager, argv0, (char *)0) < 0)  err_sys("execl error for %s", pager); //执行分页程序

     }

exit(0);

}

   在APUE中执行:

             

  执行过程:  

  子进程负责获取标准输入agrv[1]文件(文件供给分页程序作为参数)并执行分页程序的结果读到管道;

  父进程负责获取agrv[1]文件中内容并写到管道(分页程序);

 

 将子进程中dup2操作注释到后执行: 

........

if (fd[0] != STDIN_FILENO)

{

/*if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)

 err_sys("dup2 error to stdin");

//close(fd[0]); /* don't need this after dup2 */

}

........

             执行结果:

                 

              若将父进程中的write注释掉,执行则无任何打印就退出.

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值