管道?
这个东西用来干嘛?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.若无读者在读取数据,则写操作执行失败