现在的位置: 首页 > 综合 > 正文

pipe小示例

2013年10月26日 ⁄ 综合 ⁄ 共 2856字 ⁄ 字号 评论关闭

管道?

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

抱歉!评论已关闭.