必威体育Betway必威体育官网
当前位置:首页 > IT技术

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

时间:2019-10-19 15:12:14来源:IT技术作者:seo实验室小编阅读:82次「手机版」
 

命名管道

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

》mkfifo命令创建一个FIFO特殊文件,是一个命名管道(可以用来做进程之间通信的桥梁)

》管道也是一种文件,一般是linux中的一个页大小,4k,管道数据一旦被读取就没了。(管道大小和管道的buff大小理解有错误,请看 pipe-buffer-size-is-4k-or-64k? )

》管道是单方向

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时增加标志位就可以了。

使用命名管道

下面均是再OSX系统实验。

创建管道

liuzhizhi@lzz-rmbp|pipe # mkfifo log.pipe

1

查看管道

liuzhizhi@lzz-rmbp|pipe # ls -l
total 0
prw-r--r-- 1 liuzhizhi staff 0 10 14 22:21 log.pipe
1
2
3

仔细看下最前面的部分 开头是 p,表示这是一个管道

使用管道

一对一的情况

#第一个窗口

# ls -l > log.pipe

#第二个窗口

# cat < log.pipe
total 0
prw-r--r-- 1 liuzhizhi staff 0 10 14 22:25 log.pipe
1
2
3
4
5
6
7

这里管道并不是水桶,当我们执行 ls -l > log.pipe 的时候,这里就开始阻塞了,只有当我们再第二个窗口执行 cat < log.pipe 的时候,第一个窗口的ls命令才执行完。

所以这里的管道非常形象,它只是负责传输,虽然它也能存点水,但只有实用的时候才能存住一点水,如果只有一端倒水或者只有一端接水,都是无法正常运行的。

一个输入,多个接收的情况

#窗口1 

cat < log.pipe

#窗口2 

cat < log.pipe

#窗口3

echo "lzz" > log.pipe
1
2
3
4
5
6
7
8

执行的结果是窗口2输出了 lzz,第一个窗没有输出,说明接收方无论多个只能获取一份水,只要被一个接收方接受到,另外一个就无法获取了(所以他不是订阅型的),通过持续往管道输入可以看到,接收方应该是基于抢占式的。

多个输入,一个接受的情况

这里写了一个Python程序来做为持续的输入

#coding:utf-8
#logpipe.py
import time
import sys

word = sys.argv[1]

while 1:
    print >> sys.stdout, word
    time.sleep(1)
1
2
3
4
5
6
7
8
9
10

测试

#窗口1 

cat < log.pipe

#窗口2 

python logpipe.py win1 > log.pipe

#窗口3 

python logpipe.py win2 > log.pipe

#输出

win2
win2
win2
win2
win1
win1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

其实这种情况,比较好理解,有个下水道大家都往里面倒水,最后汇总到一个口流出来,由于有缓冲区,所以并不会马上读取到结果。

小结

当然我们这里是用bash 操作这个命名管道,其实基本所有的语言都可以使用这个工具,例如bash命令写入管道,python读取,lua读取。

相关阅读

linux中显示中文乱码如何解决?

#第一步-排查 #第1个里程碑-看看linux系统的字符集 echo $LANG#第2个里程碑-远程连接工具 xshell/SecureCRT/putty 字符集#第二步

【linux基础】 find的用法

1. 根据文件名查找: 如查找当前目录下名为"programer"的文件: 2.根据文件类型查找 如下是查当前目录下的目录: 3.根据文件大小

Linux tcpdump命令详解

简介 用简单的话来定义tcpdump,就是:dump the traffic on a network,根据使用者的定义对网络上的数据包进行截获的包分析工具。 tc

Linux系统下Oracle数据库自动备份脚本经验分享

1、新建Oracle数据库备份目录mkdir -p /backup/oracledata  2、新建Oracle数据库备份脚本vi /backup/oracledata/ordatabak.sh 

Linux新手的选择:Deepin(深度操作系统)

对于刚刚开始Linux学习生涯的新手来说,上百款让人眼花缭乱的Linux发行版中,Deepin无疑是最合适的的那一款。可能有人会问,为什么不是

分享到:

栏目导航

推荐阅读

热门阅读