管道?
这个东西用来干嘛?windows下好像没有这个东西哦,是的windows下我是没有见过,不过linux下可是有这个东西的,本来我也不知道这个是干嘛用的。。。
突然间脑子里浮现了 dmesg | grep 这个中间 | 让我想起了管道分开过滤,总体显示吧?貌似是这样的,其他的应用我就不清楚了
首先给个例子吧
#include <stdio.h> #include <unistd.h> int main() { int len,i,apipe[2]; char buf[BUFSIZ]; if(pipe(apipe)==-1){ perror("could not make pipe"); exit(1); } printf("Got a pipe! It is file descriptors:{ %d %d }\n", apipe[0],apipe[1]); /*read from stdin,write into pipe ,read from pipe,print */ while(fgets(buf,BUFSIZ,stdin)){ len=strlen(buf); if(write(apipe[1],buf,len)!=len){//send down pipe perror("writing to pipe"); break; } for(i=0;i<len;i++) buf[i]='X'; printf("send down pipe\n"); len=read(apipe[0],buf,BUFSIZ);//read from pipe if(len == -1){ perror("reading from pipe"); break; } printf("read from pipe\n"); if(write(1,buf,len)!=len){//send to pipe 1 represent stdout perror("writing to stdout"); break; } printf("send to pipe\n"); } }
这个小例子展示了如何创建管道并使用管道来向自己发送数据。
pipe(apipe) ;用来创建管道。apipe[0],apipe[1]即为管道的描述符。
apipe[0] 为读数据端文件描述符
apipe[1]为写数据端文件描述符
stdin 的描述符是 0
stdout 的描述符是 1
stderr的描述符是 2
fork() 与管道
#include <stdio.h> #define CHILD_MESS "I want a cookie\n" #define PAR_MESS "testing..\n" #define oops(m,x) {perror(m);exit(x);} int main(int argc,char *argv[]) { int pipefd[2]; /*the pipe*/ int len; /*for write*/ char buf[BUFSIZ];/*for read*/ int read_len; if(pipe(pipefd) == -1) oops("Cannot get a pipe",1); switch(fork()){ case -1: oops("cannot fork",2); /*child writes to pipe every 5 seconds*/ case 0: len=strlen(CHILD_MESS); while(1){ if(write(pipefd[1],CHILD_MESS,len)!=len) oops("write",3); sleep(5); } /*parent reads from pipe and also writes to pipe*/ default: len=strlen(PAR_MESS); while(1){ if(write(pipefd[1],PAR_MESS,len)!=len) oops("write",4); sleep(1); read_len=read(pipefd[0],buf,BUFSIZ); if(read_len <= 0) break; write(1,buf,read_len); } } }
这些例子,仅仅用来学习还可以,真正实用的谁知道怎么写呢
来看看下面来一个具体的例子看看
#include <stdio.h> #include <unistd.h> #define oops(m,x) {perror(m),exit(x);} int main(int ac,char *av[]) { int thepipe[2], /*two file descriptors*/ newfd, /*useful for pipes*/ pid; /*and the pid*/ if(ac!=3){ fprintf(stderr,"usage:pipe cmd1 cmd2\n"); exit(1); } if(pipe(thepipe) == -1){ oops("cannot get a pipe",1); } /*now we have pipe ,so we can get the two process*/ if((pid=fork()) == -1 ) oops("cannot fork",2); /*right here ,there are two processes parent will read from pipe*/ if(pid>0){ close(thepipe[1]); if(dup2(thepipe[0],0) == -1) oops("could not redirect stdin",3); close(thepipe[0]); /*stdin is duped ,close pipe*/ execlp(av[2],av[2],NULL); oops(av[2],4); } /*child execs av[1] and writes into pipe*/ close(thepipe[0]); /*stdout is duped ,close pipe*/ execlp(av[1],av[1],NULL); oops(av[1],5); }
pipe.c 用了和shell一样的思路和技术来创建管道,但是shell 并不像pipe.c 一样运行外部程序。shell 首先创建管道,然后调用fork 创建两个新进程,再将标准输入和输出重定向到创建的管道,最后通过exec来执行两个程序。
技术细节
管道并非文件
从管道中读数据
1.管道读取阻塞,当进程试图读取管道中的数据时,进程被挂起直到数据被写进管道。
2.管道的读取结束标志,当所有的写者关闭了管道的写数据端时,试图从管道读取数据的调用返回0,这意味着文件的结束。
3.多个读者可能会引起麻烦,管道是一个队列,当两个进程同时读的时候,一个进程读过后数据没了,另一个进程再读的时候数据明显不完整,当然您可以想办法协调。
向管道中写数据
1.写入数据阻塞直到管道有空间去容纳新的数据
2.写入必须保证一个最小的块的大小,POSIX规定内核不会拆分小于512字节的块。而linux则保证管道中可以存在4096自己的连续缓存,如果两个进程向管道写数据,并且每个进程都限制其消息不大于512字节,那么这些消息都不会被内核拆分。
3.若无读者在读取数据,则写操作执行失败