Linux管道的一些细节

读管道:

    1、进程从管道中读取数据时,进程被挂起直到数据被写进管道。(如果管道被两个进程共享,进程A关闭了读端,进程B读写都开启,B使用读端时,会一直等待B进程的写端的动作,而不会理会A的动作。)

    2、当所有的写者关闭了管道的写数据端时,试图从管道中读取数据的调用返回0,意味着文件结束。

    3、管道是一个队列。一个进程从管道中读取数据后,数据已经不存在了。如果两个进程都试图对同一个管道进行度操作,在一个读取一些之后,另一个进程读到的将是后面的内容。他们读到的数据必然是不完整的,除非两个进程用某种方式来协调它们对管道的访问。


写管道:

    1、管道容纳的数据量是有限的,比磁盘文件差很多。如果进程想写入1000个字节,而管道只能容纳500个,那么写入调用只能等待,直到管道中再有500个字节。

    2、当所有读者都关闭读数据端,则写操作失败。首先内核发送SIGPIPE消息给进程。若进程被终止,则无任何事情发生,否则write调用返回-1,并且将errno置为EPIPE。

    3、POSIX标准规定内核不会拆分小于512字节的块。而Linux则保证管道中可以存在4096字节的连续缓存。如果两个进程向管道写数据,并且每一个进程都限制其消息不大于512字节,那么这些消息都不会被内核拆分。

    这个示例程序,简单地展示了管道的使用:

/*
 * @FileName: pipedemo.c
 * @Author: wzj
 * @Brief: 
 *  
 * @History: 
 * 
 * 
 * 
 * @Date: 2011年10月04日星期二18:55:23
 * 
 */ 
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>

int main()
{
	int 	len, i, apipe[2];
	char 	buf[BUFSIZ];
	int 	tmfd;

//	tmfd = open("/etc/passwd", O_RDONLY);
//	dup2(tmfd, 2); // redirect output...
//	close(tmfd);
//	close(0);     // can't get the input...
//	close(1);   // can't output...

	close(2);
	/*get a pipe*/
	if(pipe(apipe) == -1)
	{
		perror("could not make pipe");
		exit(1);
	}

	printf("Got a pipe ! It is file descriptors: \
			{ %d %d} BUFSIZE:%d\n", apipe[0], apipe[1], BUFSIZ);
	
	/*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)
		{
			perror("writing to pipe");
			break;
		}

		for(i=0; i<len ; i++)
		{
			buf[i] = 'X';
		}
		len = read(apipe[0], buf, BUFSIZ);
		if(len == -1)
		{
			perror("reading from pipe");
			break;
		}

		if(write(1, buf, len) != len)
		{
			perror("writing to stdout");
			break;
		}
	}

	return 0;
}

下面这个程序演示了,如果所有读者都关闭的时候,写者进行写操作就会错误。子进程尝试写,失败后内核发出SIGPIPE信号。当处理了SIGPIPE时,write返回-1,未处理,子进程直接退出,父进程可以查看到他的状态。

/*
 * @FileName: pipe.c * @Author: wzj
 * @Brief: 
 *  
 * @History: 
 * 
 * 
 * 
 * @Date: 2011年10月04日星期二19:44:40
 * 
 */ 
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>

#define CHILD_EXT(x)	((x)>>8)	//child exit value
#define CHILD_SIG(x)	((x)& 0x7f)	//child signal 	
#define CHILD_SEGV(x)	((x)& 0x80)	//segment fault 
#define oops(m,x) {perror(m); exit(x);}

void showpipe(int signum)
{
	fprintf(stderr,"pipe got the error!!!!!\n");
}

int main(int ac, char** av)
{
	int 	thepipe[2],
			newfd,
			pid;
	int 	result;

//	signal(SIGPIPE, showpipe);    // catch the SIGPIPE

	if(pipe(thepipe) == -1)
		oops("Can't get a pipe", 1);
	
	if((pid = fork()) == -1)
	{
		oops("Cannot fork", 1);
	}
	
	close(thepipe[0]);

	if(pid > 0) // parent
	{
		close(thepipe[1]);
		wait(&result);
		
		printf("%d,%d,%d\n", 
			CHILD_EXT(result), 
			CHILD_SIG(result), 
			CHILD_SEGV(result));
	}
       
	if(pid == 0) //child
	{
		if(write(thepipe[1], "asdf", 4) == -1)
		{
			fprintf(stderr,"write pipe failed\n");
		}
			fprintf(stderr,"after pipe\n");
	}	
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值