接上一篇的无名管道,今天总结一下进程间通信的有名管道。
有名管道可以克服无名管道的一个限制,即因为没有具体的名字,它只能用于具有亲缘关系的进程间的通信。原因是有名管道提供了一个路径名与之关联,并以FIFO的文件形式存在于文件系统中。于是,即使与FIFO的创建进程不存在亲缘关系的进程,只要有可以访问该路径,FIFO就可以为它们提供通信,所以有名管道不仅可以用于有亲缘关系间的通信,也可以用于无亲缘进程之间的通信。
FIFO严格遵循先进先出的原则,对管道以及FIFO的读取总是从开始处返回数据的,对它们进行写操作时,则把数据添加到末尾处,并且它不支持lseek()函数等文件定位操作。
mkfifo()
功能:创建有名管道
头文件:#include <sys/types.h>
#include <sys/stat.h>
原型:int mkfifo(char *pathname,mode_t mode)
说明:创建的文件必须在创建前不存在;
mode是该文件的权限
返回值:成功,返回0;失败,返回-1.
从FIFO中读取数据:
约定:如果一个进程为了从FIFO中读取数据而打开FIFO,那么称该进程内的读操作为设置了阻塞标志的读操作。
1、如果FIFO中有数据,则设置了阻塞标志的读操作不会因为FIFO中的字节数小于请求读的字节数而堵塞,只会返回现在FIFO中实际有的数据量;
2、如果有进程写打开FIFO,且当前FIFO内没有数据,则对于设置了阻塞标志的读操作来说,将一直处于阻塞。对于没有设置阻塞标志的读操作来说则会返回-1,当前errno值为EAGAIN,提醒再试;
3、对于设置了阻塞标志的读操作来说,造成阻塞有两种原因:当前FIFO内有数据,但有其他进程在读这些数据;另外就是FIFO内没有数据。不阻塞的原因则是FIFO中国有新的数据写入,不论写入的数据量的大小,也不论读操作请求多少数据量;
4、读打开的阻塞标志只对本进程第一个读操作起作用,如果本进程内有多个读操作序列,则在第一个读操作被唤醒并完成读操作后,其他将要执行的读操作将不再阻塞,即使在执行读操作时,FIFO中没有数据也一样,读操作返回0;
5、如果没有进程写打开FIFO,则设置了阻塞标志的读操作会阻塞。
向FIFO中写入数据:
约定:如果一个进程为了向FIFO中写入数据而阻塞打开FIFO,那么称该进程内的写操作为设置了阻塞标志的写操作。
1、对于设置了阻塞标志的写操作:
(1)当要写入的数据量不大于PIPE_BUF时,Linux将保证其写入的原子性。如果此时管道空闲缓冲区不足以容纳要写入的字节数,则进入睡眠,直到当缓冲区能够容纳要写入的字节数时,才开始进行一次性写操作;
(2)当要写入的数据量大于PIPE_BUF时,Linux将不会再保证写入的原子性。FIFO缓冲区一有空闲区域,写进程就会试图向管道写入数据,写操作在写完所有的请求写的数据后返回。
2、对于没有设置阻塞标志的写操作:
(1)当要写入的数据量大于PIPE_BUF时,Linux将不再保证写入的原子性。在写满所有的FIFO空闲缓冲区后,写操作返回;
(2)当要写入的数据量不大于PIPE_BUF时,Linux将保证写入的原子性。如果当前FIFO空闲缓冲区能够容纳请求写入的字节数,写完后成功返回;如果当前FIFO空闲缓冲区不能够容纳请求写入的字节数,则返回EAGAIN错误,提醒以后再写。