管道文件
- pipe
#include <unistd.h>
int pipe(int fildes[2]);
调用成功后,可以访问两个文件描述符,fildes[0]是用来读的文件描述符,而fildes[1]是用来写的文件描述符。
pipe仅允许单向通信,fildes[0]只用来读,fildes[1]只用来写。若要双向通信,必须创建两组管道。
在实际使用中,通过创建一个子进程,然后一个进程写,一个进程读来使用。
必须在fork()前调用pipe(),否则子进程不会继承文件描述符。两个进程不共享祖先进程,就不能使用pipe。但是可以使用命名管道。
当管道进行写入操作的时候,如果写入的数据小于128K则是非原子的,如果大于128K字节,缓冲区的数据将被连续地写入
管道,直到全部数据写完为止,如果没有进程读取数据,则将一直阻塞。
虽然管道是一种特殊的文件,它的读写操作和普通文件的读写操作完全一样,但管道不是一个真实存在的文件,它只在内核中存储,而不存在于文件系统中。
- dup2
int dup2(int oldfd, int newfd);
dup2将永oldfd文件描述符来代替newfd文件描述符,同时关闭newfd文件描述符。也就是说,所有指向newfd的操作都转到oldfd上面。
- 命名管道FIFO
命名管道又称先入先出队列,是一种特殊的管道,存在于文件系统中。其显著特点:
》命名管道可以用于任何两个进程间的通信,并不限制于两个进程同源。
》命名管道作为一种特殊的文件存放于文件系统中,而不是像管道一样存放于内核中。当进程对命名管道使用结束后,命名管道依然存在于文件系统中,除非对其进行删除,否则该命名管道不会消失。
和管道一样,命名管道也仅允许单向通信,若要双向通信,必须创建两组命名管道。
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
mode与创建普通文件的create()的mode相似,成功返回0,失败返回-1。
int mknod(char *pathname, mode_t mode, dev_t dev);
mknod不是一个专门用于创建命名管道的函数,参数pathname/mode和mkfifo相同,dev取0。成功0,失败-1。
shell命令创建命名管道:
mkfifo FIFO_TEST
mknod FIFO_TEST p
可以像普通文件一样,open/read/write/close fifo。
使用命名管道与管道的注意问题一样:
》向未打开或已经关闭的管道进行写操作,将产生SIGPIPE信号,write函数将errno设置为出错值。
》系统定义的常量PIPE_BUF规定了命名管道缓冲的大小,当写入数据超过规定大小后,将会使数据发生交错。
》当一个进程从命名管道中读取数据时,如果命名管道中的全部数据读完了,read()认为读到了文件末尾,返回值为0。但有可能数据的写入并没有结束,写入命名管道的进程还有数据要传输。因此要分清楚是数据传输结束还是暂时无数据读取,如果是后者,则读取数据的进程应等待。
注:使用命名管道时,需要在两个进行通信的进程中分别打开命名管道。因此,当一个进程读打开(或写打开)一个fifo而没有其他进程写打开(或读打开)此fifo时,该进程就会阻塞,直到另一个进程写打开(或读打开)此fifo。
若要删除一个命名管道,使用unlink。