打开文件linux系统编程之管道(三):命名管道FIFO和mkfifo函数

近期一直在研究打开文件之类的问题,上午正好有机会和大家共享一下.

    进程间通信必须通过内核提供的通道,而且必须有一种办法在进程中标识内核提供的某个通道,后面讲过的匿名管道是用打开的文件描述符来标识的。如果要互相通信的几个进程没有从公共先人那里继承文件描述符,它们怎么通信呢?内核提供一条通道不成问题,问题是如何标识这条通道才能使各进程都可以访问它?文件系统中的路径名是全局的,各进程都可以访问,因此可以用文件系统中的路径名来标识一个IPC通道。

    

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

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

    ....................

    文件类型s表示socket,这些文件在磁盘上也没有数据块。

    

    一、定名管道(FIFO)

    匿名管道应用的一个制约就是只能在拥有独特先人(拥有亲缘关系)的进程间通信。
如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为定名管道。

    定名管道可以从命令行上创建,命令行方法是使用下面这个命令:
$ mkfifo filename
定名管道也可以从程序里创建,相关函数有:
int mkfifo(const char *filename,mode_t mode);

    

    二、定名管道和匿名管道

    匿名管道由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.

    

    三、定名管道的打开规则

    如果以后打开操纵是为读而打开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: [email protected]
    > 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: [email protected]
    > 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且进程已经关闭文件描述符时,文件将被删除。

    

文章结束给大家分享下程序员的一些笑话语录: Bphone之你们聊,我先走了!移动说:我在phone前加o,我叫o缝;苹果说:我在phone前i,我是i缝;微软说:我在phone前加w,我叫w缝;三星说:你们聊,我先走了!
将来王建宙写回忆录的时候,一定要有一句“常小兵为中国移动的发展做出了不可磨灭的贡献”。

你可能感兴趣的:(linux)