Linux管道的一些细节

来源:互联网 发布:知天下吧 ztx8.net 编辑:程序博客网 时间:2024/05/22 11:12

读管道:

    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 SIGPIPEif(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;}