命名管道FIFO和mkfifo函數

進程間通訊必須經過內核提供的通道,並且必須有一種辦法在進程中標識內核提供的某個通道,前面講過的匿名管道是用打開的文件描述符來標識的。若是要互相通訊的幾個進程沒有從公共祖先那裏繼承文件描述符,它們怎麼通訊呢?內核提供一條通道不成問題,問題是如何標識這條通道才能使各進程均可以訪問它?文件系統中的路徑名是全局的,各進程均可以訪問,所以能夠用文件系統中的路徑名來標識一個IPC通道。
node


FIFO和UNIX Domain Socket這兩種IPC機制都是利用文件系統中的特殊文件來標識的。
小程序

FIFO文件在磁盤上沒有數據塊,僅用來標識內核中的一條通道,如 prw-rw-r-- 1 simba simba      0 May 21 10:13 p2,文件類型標識爲p表示FIFO,文件大小爲0。各進程能夠打開這個文件進行read/write,其實是在讀寫內核通道(根本緣由在於這個file結構體所指向的read、write函數和常規文件不同),這樣就實現了進程間通訊。UNIX Domain Socket和FIFO的原理相似,也須要一個特殊的socket文件來標識內核中的通道,例如/run目錄下有不少系統服務的socket文件:socket

srw-rw-rw- 1 root       root          0 May 21 09:59 acpid.socket
函數

....................測試

文件類型s表示socket,這些文件在磁盤上也沒有數據塊。
spa


1、命名管道(FIFO).net

匿名管道應用的一個限制就是隻能在具備共同祖先(具備親緣關係)的進程間通訊。
若是咱們想在不相關的進程之間交換數據,可使用FIFO文件來作這項工做,它常常被稱爲命名管道。
命令行

命名管道能夠從命令行上建立,命令行方法是使用下面這個命令:
$ mkfifo filename
命名管道也能夠從程序裏建立,相關函數有:
int mkfifo(const char *filename,mode_t mode);
blog


2、命名管道和匿名管道繼承

匿名管道由pipe函數建立並打開。
命名管道由mkfifo函數建立,打開用open。
FIFO(命名管道)與pipe(匿名管道)之間惟一的區別在它們建立與打開的方式不一樣,這些工做完成以後,它們具備相同的語義。

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.


3、命名管道的打開規則

若是當前打開操做是爲讀而打開FIFO時
O_NONBLOCK disable:阻塞直到有相應進程爲寫而打開該FIFO
O_NONBLOCK enable:馬上返回成功
若是當前打開操做是爲寫而打開FIFO時
O_NONBLOCK disable:阻塞直到有相應進程爲讀而打開該FIFO
O_NONBLOCK enable:馬上返回失敗,錯誤碼爲ENXIO


須要注意的是打開的文件描述符默認是阻塞的,你們能夠寫兩個很簡單的小程序測試一下,主要也就一條語句

int fd = open("p2", O_WRONLY); 假設p2是命名管道文件,把打開標誌換成 O_RDONLY 就是另外一個程序了,能夠先運行RD程序,此時會阻塞,再在另外一個窗口運行WR程序,此時兩個程序都會從open返回成功。非阻塞時也不難測試,open時增長標誌位就能夠了。


須要注意的是 命令管道與匿名管道的讀寫規則是同樣的,參見這裏


下面示例命名管道完成拷貝文件的功能:

 

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 
/*************************************************************************
    > File Name: process_.c
    > Author: Simba
    > Mail: dameng34@163.com
    > Created Time: Sat 23 Feb 2013 02:34:02 PM CST
 ************************************************************************/
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

int main(int argc, char *argv[])
{
    mkfifo("tp", 0644);
    int infd = open("Makefile", O_RDONLY);
    if (infd == -1)
        ERR_EXIT("open error");

    int outfd;
    outfd = open("tp", O_WRONLY);
    if (outfd == -1)
        ERR_EXIT("open error");

    char buf[1024];
    int n;
    while ((n = read(infd, buf, 1024)) > 0)
        write(outfd, buf, n);

    close(infd);
    close(outfd);

    return 0;
}


程序使用mkfifo函數建立一個命名管道文件tp,將Makefile 的文件都讀取到tp文件中。


 

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 
/*************************************************************************
    > File Name: process_.c
    > Author: Simba
    > Mail: dameng34@163.com
    > Created Time: Sat 23 Feb 2013 02:34:02 PM CST
 ************************************************************************/
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

int main(int argc, char *argv[])
{

    int outfd = open("Makefile2", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (outfd == -1)
        ERR_EXIT("open error");

    int infd;
    infd = open("tp", O_RDONLY);
    if (infd == -1)
        ERR_EXIT("open error");

    char buf[1024];
    int n;
    while ((n = read(infd, buf, 1024)) > 0)
        write(outfd, buf, n);

    close(infd);
    close(outfd);
    unlink("tp"); // delete a name and possibly the file it refers to
    return 0;
}

 

能夠看到跟上面的程序是相反的,即從tp讀取到Makefile2,完成拷貝文件的功能,這裏用到了一個unlink函數,屬於inode_operations系列的一個函數,即inode引用計數減1,當引用計數爲0且進程已經關閉文件描述符時,文件將被刪除。


參考:《APUE》

相關文章
相關標籤/搜索