博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
linux系统编程:命名管道FIFO和mkfifo函数
阅读量:6224 次
发布时间:2019-06-21

本文共 3711 字,大约阅读时间需要 12 分钟。

hot3.png

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

转载于:https://my.oschina.net/xiaot99/blog/365002

你可能感兴趣的文章
Python sql注入 过滤字符串的非法字符
查看>>
Spring学习笔记——Spring依赖注入原理分析
查看>>
平衡小车项目解读日志
查看>>
[1]朝花夕拾-JAVA类的执行顺序
查看>>
常用shell命令
查看>>
[js高手之路] vue系列教程 - vue的基本用法与常见指令(1)
查看>>
glGetString(GL_VERSION) returns “OpenGL ES-CM 1.1” but my phone supports OpenGL 2
查看>>
RDA PQ工具使用 (屏参调整)
查看>>
Servlet学习笔记(三):HTTP请求与响应
查看>>
HttpClient request payload post请求
查看>>
MySQL慢查询
查看>>
Bootstrap树控件(Tree控件组件)使用经验分享
查看>>
Linux搭建JavaEE开发环境与Tomcat——(十)
查看>>
JFinal 学习笔记之Handler包分析
查看>>
Redis总结(六)Redis配置文件全解
查看>>
“四核”驱动的“三维”导航 -- 淘宝新UI(需求分析篇)
查看>>
iOS开发如何在一个透明视图上添加不透明的子控件
查看>>
加解密
查看>>
Cortex-A9 UART
查看>>
envoy 功能介绍
查看>>