linux系統編程:命名管道FIFO和mkfifo函數

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


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

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文件: 函數

srw-rw-rw- 1 root       root          0 May 21 09:59 acpid.socket
測試

.................... spa

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


1、命名管道(FIFO) 命令行

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

命名管道能夠從命令行上建立,命令行方法是使用下面這個命令:
$ 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; }
相關文章
相關標籤/搜索