管道文件操作

管道文件

1. pipe

#include <unistd.h>
int pipe(int fildes[2]);

调用成功后,可以访问两个文件描述符,fildes[0]是用来读的文件描述符,而fildes[1]是用来写的文件描述符。

pipe仅允许单向通信,fildes[0]只用来读,fildes[1]只用来写。若要双向通信,必须创建两组管道。

在实际使用中,通过创建一个子进程,然后一个进程写,一个进程读来使用。

必须在fork()前调用pipe(),否则子进程不会继承文件描述符。两个进程不共享祖先进程,就不能使用pipe。但是可以使用命名管道。

当管道进行写入操作的时候,如果写入的数据小于128K则是原子的,如果大于128K字节,缓冲区的数据将被连续地写入

管道,直到全部数据写完为止,如果没有进程读取数据,则将一直阻塞。

虽然管道是一种特殊的文件,它的读写操作和普通文件的读写操作完全一样,但管道不是一个真实存在的文件,它只在内核中存储,而不存在于文件系统中。

2. dup2

int dup2(int oldfd, int newfd);

dup2将永oldfd文件描述符来代替newfd文件描述符,同时关闭newfd文件描述符。也就是说,所有指向newfd的操作都转到oldfd上面。

3. 命名管道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。

注:使用命名管道时,需要在两个进行通信的进程中分别打开命名管道。因此,当一个进程读打开(或写打开)一个fifo而没有其他进程写打开(或读打开)此fifo时,该进程就会阻塞,直到另一个进程写打开(或读打开)此fifo。

若要删除一个命名管道,使用unlink。

4. 使用注意 

使用命名管道与管道的注意问题一样:

》向未打开或已经关闭的管道进行写操作,将产生SIGPIPE信号,write函数将errno设置为出错值。

》当一个进程从命名管道中读取数据时,如果命名管道中的全部数据读完了,read()认为读到了文件末尾,返回值为0。但有可能数据的写入并没有结束,写入命名管道的进程还有数据要传输。因此要分清楚是数据传输结束还是暂时无数据读取,如果是后者,则读取数据的进程应等待。

系统定义的常量PIPE_BUF规定了命名管道缓冲的大小,当写入数据超过规定大小后,将会使数据发生交错。ulimit -a显示PIPE_BUF值(Ubuntu16.04)为512bytes * 8 = 4096 bytes。

POSIX.1规定当写入管道的长度小于PIPE_BUF字节时必须是原子的:即写入数据作为连续序列写入管道。 超过PIPE_BUF字节的写入可能是非原子的:内核可能会将数据与其他进程写入的数据交错。

POSIX.1要求PIPE_BUF至少为512字节。(在Linux上,PIPE_BUF为4096字节)。在实践中取决于文件描述符是否为非阻塞(O_NONBLOCK),管道中是否有多个写入器,以及n要写入的字节数:

n <= PIPE_BUF, O_NONBLOCK无效:原子的写入n个字节。如果管道当前的剩余空间不足以立即写入n个字节,就阻塞直到有足够的空间。

n <= PIPE_BUF, O_NONBLOCK有效:写入具有原子性,如果有足够的空间写入n个字节,write立即成功返回。否则一个都不写入,返回错误,并设置errno为EAGAIN。

n > PIPE_BUF, O_NONBLOCK无效:非原子写。可能会和其它的写进程交替写。write阻塞直到将n个字节写入管道。

n > PIPE_BUF, O_NONBLOCK有效:如果管道满,则write失败,返回错误,并将errno设置为 EAGIN。如果不满,则返回写入的字节数为1~n,即部分写入,写入时可能有其他进程穿插写入。

结论: 1、当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。 2、当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

posted @ 2015-12-14 21:08  yuxi_o  阅读(1348)  评论(0编辑  收藏  举报