管道的主要侷限性正體如今它的特色上: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