管道的主要局限性正体如今它的特色上:html
若是咱们想在不相关的进程之间交换数据,可使用FIFO文件来作这项工做,它常常被称为命名管道,是一种特殊类型的文件。linux
管 道应用的一个重大限制是它没有名字,所以,只能用于具备亲缘关系的进程间通讯,在有名管道(named pipe或FIFO)提出后,该限制获得了克服。FIFO不一样于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即 使与FIFO的建立进程不存在亲缘关系的进程,只要能够访问该路径,就可以彼此经过FIFO相互通讯(可以访问该路径的进程以及FIFO的建立进程之 间),所以,经过FIFO不相关的进程也能交换数据。值得注意的是,FIFO严格遵循先进先出(first in first out),对管道及FIFO的读老是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()等文件定位操做。app
命名管道能够从命令行上建立,命令行方法是使用下面这个命令: 函数
$ mkfifo filename this
命名管道也能够从程序里建立,相关函数有:spa
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char * pathname, mode_t mode)
该函数的第一个参数是一个普通的路径名,也就是建立 后FIFO的名字。第二个参数与打开普通文件的open()函数中的mode 参数相同。 若是mkfifo的第一个参数是一个已经存在的路径名时,会返回EEXIST错误,因此通常典型的调用代码首先会检查是否返回该错误,若是确实返回该错 误,那么只要调用打开FIFO的函数就能够了。通常文件的I/O函数均可以用于FIFO,如close、read、write等等。.net
man帮助说明:命令行
mkfifo() makes a FIFO special file with name pathname. mode specifies the FIFO's permissions. It is modified by the process's umask in the usual way: the permissions of the created file are (mode & ~umask). A FIFO special file is similar to a pipe, except that it is created in a different way. Instead of being an anonymous communications channel, a FIFO special file is entered into the file system by calling mkfifo(). Once you have created a FIFO special file in this way, any process can open it for reading or writing, in the same way as an ordinary file. However, it has to be open at both ends simultaneously before you can proceed to do any input or output operations on it. Opening a FIFO for reading normally blocks until some other process opens the same FIFO for writing, and vice versa. See fifo(7) for nonblocking handling of FIFO special files.
On success mkfifo() returns 0. In the case of an error, -1 is returned (in which case, errno is set appropriately).
FIFO(命名管道)与pipe(匿名管道)之间惟一的区别在它们建立与打开的方式不一样,一量这些工做完成以后,它们具备相同的语义。code
man帮助说明:The only difference between pipes and FIFOs is the manner in which they are created and opened. Once these tasks have been accomplished, I/O on pipes and FIFOs has exactly the same semantics。orm
有名管道比管道多了一个打开操做:open。
FIFO的打开规则:
若是当前打开操做是为读而打开FIFO时,若已经有相应进程为写而打开该FIFO,则当前打开操做将成功返回;不然,可能阻塞直到有相应进程为写而打开该FIFO(当前打开操做设置了阻塞标志);或者,成功返回(当前打开操做没有设置阻塞标志)。
若是当前打开操做是为写而打开FIFO时,若是已经有相应进程为读而打开该FIFO,则当前打开操做将成功返回;不然,可能阻塞直到有相应进程为读而打开该FIFO(当前打开操做设置了阻塞标志);或者,返回ENXIO错误(当前打开操做没有设置阻塞标志)。
从FIFO中读取数据:
约定:若是一个进程为了从FIFO中读取数据而阻塞打开FIFO,那么称该进程内的读操做为设置了阻塞标志的读操做。
注:若是FIFO中有数据,则设置了阻塞标志的读操做不会由于FIFO中的字节数小于请求读的字节数而阻塞,此时,读操做会返回FIFO中现有的数据量。
向FIFO中写入数据:
约定:若是一个进程为了向FIFO中写入数据而阻塞打开FIFO,那么称该进程内的写操做为设置了阻塞标志的写操做。
对于设置了阻塞标志的写操做:
对于没有设置阻塞标志的写操做:
示例一:建立FIFO文件
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> int main(int argc, char **argv) { if(argc != 2){ fprintf(stderr,"usage:%s fifoname\n",argv[0]); exit(EXIT_FAILURE); } if(mkfifo(argv[1],0644) == -1){ perror("mkfifo error"); exit(EXIT_FAILURE); } printf("creat FIFO success\n"); return 0; }
结果:
示例二:若是当前打开操做是为读而打开FIFO时,若已经有相应进程为写而打开该FIFO,则当前打开操做将成功返回;不然,可能阻塞直到有相应进程为写而打开该FIFO(当前打开操做设置了阻塞标志);或者,成功返回(当前打开操做没有设置阻塞标志)。
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> int main(int argc, char **argv) { int fd; //fd = open("mypipe",O_RDONLY| O_NONBLOCK);//非阻塞模式打开 fd = open("mypipe",O_RDONLY);//默认是阻塞模式打开 if(fd == -1){ perror("open error"); exit(EXIT_FAILURE); } printf("read open FIFO success\n"); return 0; }
结果:
第一次以非阻塞打开
第二次以阻塞模式打开
示例三:若是当前打开操做是为写而打开FIFO时,若是已经有相应进程为读而打开该FIFO,则当前打开操做将成功返回;不然,可能阻塞直到有相应进程为读而打开该FIFO(当前打开操做设置了阻塞标志);或者,返回ENXIO错误(当前打开操做没有设置阻塞标志)。
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> int main(int argc, char **argv) { int fd; //fd = open("mypipe",O_WRONLY| O_NONBLOCK);//非阻塞模式打开 fd = open("mypipe",O_WRONLY);//默认是阻塞模式打开 if(fd == -1){ perror("open error"); exit(EXIT_FAILURE); } printf("read open FIFO success\n"); return 0; }
结果:
第一次以非阻塞模式打开
第二次以阻塞模式打开
示例四:不一样进程间利用命名管道实现文件复制
写管道进程:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> int main(int argc, char **argv) { if(argc != 2){ fprintf(stderr,"usage:%s srcfile\n",argv[0]); exit(EXIT_FAILURE); } int infd; infd = open(argv[1],O_RDONLY); if(infd == -1){ perror("open error"); exit(EXIT_FAILURE); } if(mkfifo("tmpfifo",0644) == -1){ perror("mkfifo error"); exit(EXIT_FAILURE); } int fd ; fd = open("tmpfifo",O_WRONLY); if(fd == -1){ perror("open error"); exit(EXIT_FAILURE); } char buf[1024*4]; int n = 0; while((n = read(infd,buf,1024*4))){ write(fd,buf,n); } close(infd); close(fd); printf("write success\n"); return 0; }
读进程:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> int main(int argc, char **argv) { if(argc != 2){ fprintf(stderr,"usage:%s desfile\n",argv[0]); exit(EXIT_FAILURE); } int outfd; outfd = open(argv[1],O_WRONLY|O_CREAT|O_TRUNC); if(outfd == -1){ perror("open error"); exit(EXIT_FAILURE); } int fd ; fd = open("tmpfifo",O_RDONLY); if(fd == -1){ perror("open error"); exit(EXIT_FAILURE); } char buf[1024*4]; int n = 0; while((n = read(fd,buf,1024*4))){ write(outfd,buf,n); } close(fd); close(outfd); unlink("tmpfifo"); printf("read success\n"); return 0; }
结果:
复制成功!
注:本文参考:http://blog.csdn.net/sooneboy/article/details/3915490