PIPE - Linux手册页

时间:2019-08-20 18:02:00  来源:igfitidea点击:

Linux程序员手册 第7部分
更新日期: 2017-09-15

名称

管道-管道和FIFO概述

说明

管道和FIFO(也称为命名管道)提供了单向进程间通信通道。管道具有读取端和写入端。可以从管道的读取端读取写入管道的写入端的数据。

使用pipe(2)创建管道,该管道创建一个新管道并返回两个文件描述符,一个文件描述符指向该管道的读取端,另一个文件描述符指向写入端。管道可用于在相关流程之间创建通信通道;有关示例,请参见pipe(2)。

fifo(先进先出的缩写)在文件系统中具有名称(使用mkfifo(3)创建),并使用open(2)打开。假设文件权限允许,则任何进程都可以打开FIFO。使用O_RDONLY标志打开读取端。使用O_WRONLY标志打开写端。有关更多详细信息,请参见fifo(7)。注意:尽管FIFO在文件系统中具有路径名,但是FIFO上的I / O不涉及对基础设备的操作(如果有)。

I/O on pipes and FIFOs

管道和FIFO之间的唯一区别是它们的创建和打开方式。完成这些任务后,管道和FIFO上的I / O具有完全相同的语义。

如果进程尝试从空管道读取,则read(2)将阻塞,直到有可用数据为止。如果某个进程尝试写入一个已满的管道(请参见下文),则write(2)会阻塞,直到从管道中读取了足够的数据以允许写入完成为止。通过使用fcntl(2)F_SETFL操作启用O_NONBLOCK打开文件状态标志,可以实现非阻塞I / O。

管道提供的通信通道是字节流:没有消息边界的概念。

如果所有引用管道写端的文件描述符都已关闭,则从管道读取(2)的尝试将看到文件结尾(read(2)将返回0)。如果所有引用管道读取端的文件描述符都已关闭,则write(2)将导致为调用过程生成SIGPIPE信号。如果调用过程忽略此信号,则write(2)失败,并显示错误EPIPE。使用pipe(2)和fork(2)的应用程序应使用适当的close(2)调用来关闭不必要的重复文件描述符;这样可以确保在适当的时候传递文件结尾和SIGPIPE / EPIPE。

无法将lseek(2)应用于管道。

Pipe capacity

管道的容量有限。如果管道已满,则write(2)将阻塞还是失败,具体取决于是否设置了O_NONBLOCK标志(请参见下文)。不同的实现对管道容量有不同的限制。应用程序不应依赖于特定的容量:应设计应用程序,以使读取过程在数据可用时立即消耗数据,从而不会阻塞写入过程。

在2.6.11之前的Linux版本中,管道的容量与系统页面大小相同(例如,在i386上为4096字节)。从Linux 2.6.11开始,管道容量为16页(即,在页面大小为4096字节的系统中为65,536字节)。从Linux 2.6.35开始,默认管道容量为16页,但是可以使用fcntl(2)F_GETPIPE_SZ和F_SETPIPE_SZ操作查询和设置容量。有关更多信息,请参见fcntl(2)。

以下ioctl(2)操作(可应用于引用管道两端的文件描述符)将计数管道中未读字节的数量,并将其放在调用的最终参数所指向的int缓冲区中:

ioctl(fd,FIONREAD,&nbytes);

FIONREAD操作未在任何标准中指定,但在许多实现中均提供。

/proc files

在Linux上,以下文件控制可用于管道的内存量:

/proc/sys/fs/pipe-max-pages(only in Linux 2.6.34)
无权限用户(一个没有CAP_SYS_RESOURCE功能的用户)可以为管道设置的容量上限(以页为单位)。
此限制的默认值是默认管道容量的16倍(请参见上文);下限是两页。
在Linux 2.6.35中已删除此接口,而改用/ proc / sys / fs / pipe-max-size。
/proc/sys/fs/pipe-max-size(since Linux 2.6.35)
没有CAP_SYS_RESOURCE功能的用户可以设置的单个管道的最大大小(以字节为单位)。分配给该文件的值可以向上舍入,以反映为方便实施而实际使用的值。要确定上舍入的值,请在为其分配值后显示此文件的内容。
该文件的默认值为1048576(1 MiB)。可以分配给该文件的最小值是系统页面大小。尝试将限制设置为小于页面大小会导致write(2)失败,并显示错误EINVAL。
从Linux 4.9开始,此文件上的值还充当新管道或新打开的FIFO的默认容量的上限。
/proc/sys/fs/pipe-user-pages-hard(since Linux 4.5)
由单个非特权用户(即既没有CAP_SYS_RESOURCE也没有CAP_SYS_ADMIN功能的用户)创建或设置的所有管道的总大小(以页为单位)的硬性限制。只要为此用户分配给管道缓冲区的页面总数达到此限制,就将拒绝创建新管道的尝试,并且拒绝增加管道容量的尝试。
当此限制的值为零(默认值)时,不应用硬限制。
/proc/sys/fs/pipe-user-pages-soft(since Linux 4.5)
由单个非特权用户(即既没有CAP_SYS_RESOURCE也没有CAP_SYS_ADMIN功能的用户)创建或设置的所有管道的总大小(以页为单位)的软限制。只要为此用户分配给管道缓冲区的页面总数达到此限制,用户创建的各个管道将被限制为一页,并且增加管道容量的尝试将被拒绝。
当此限制的值为零时,不应用软限制。该文件的默认值为16384,它允许创建多达1024个具有默认容量的管道。

在Linux 4.9之前,一些错误影响了pipe-user-pages-soft和pipe-user-pages-hard限制的处理。参见错误。

PIPE_BUF

POSIX.1说,小于PIPE_BUF字节的write(2)必须是原子的:输出数据作为连续序列写入管道。超过PIPE_BUF字节的写入可能是非原子的:内核可能会将数据与其他进程写入的数据进行交织。 POSIX.1要求PIPE_BUF至少为512个字节。 (在Linux上,PIPE_BUF为4096字节。)精确的语义取决于文件描述符是否为非阻塞(O_NONBLOCK),管道是否有多个写入器,以及在n上为要写入的字节数:

O_NONBLOCKdisabled, n<= PIPE_BUF
所有n个字节都是原子写入的;如果没有足够的空间立即写入n个字节,write(2)可能会阻塞
O_NONBLOCKenabled, n<= PIPE_BUF
如果有空间将n个字节写入管道,则write(2)立即成功,写入所有n个字节;否则,write(2)将失败,并且errno设置为EAGAIN。
O_NONBLOCKdisabled, n> PIPE_BUF
写操作是非原子的:可以通过其他过程将提供给write(2)的数据与write(2)进行交织; write(2)阻塞,直到已写入n个字节为止。
O_NONBLOCKenabled, n> PIPE_BUF
如果管道已满,则write(2)失败,errno设置为EAGAIN。否则,可能会写入1到n个字节(即可能发生"部分写入";调用方应检查write(2)的返回值以查看实际写入了多少个字节),并且这些字节可以与由其他进程写。

Open file status flags

可以有意义地应用于管道或FIFO的唯一打开文件状态标志是O_NONBLOCK和O_ASYNC。

当管道的新输入变为可用时,为管道的读取端设置O_ASYNC标志会导致生成信号(默认情况下为SIGIO)。必须使用fcntl(2)F_SETOWN命令设置信号传递的目标。在Linux上,仅从内核2.6开始,管道和FIFO就支持O_ASYNC。

Portability notes

在某些系统(但不是Linux)上,管道是双向的:数据可以在管道两端之间双向传输。 POSIX.1仅需要单向管道。可移植的应用程序应避免依赖双向管道语义。

BUGS

在Linux 4.9之前,使用fcntl(2)F_SETPIPE_SZ操作更改管道容量时,一些错误影响了pipe-user-pages-soft和pipe-user-pages-hard限制的处理:

(1)
当增加管道容量时,将根据现有消耗量对软限制和硬限制进行检查,并且不包括增加管道容量所需的内存。然后,管道容量的新增加可能会使用户用于管道的总内存(可能远远超过)超出限制。 (这也可能引发下面描述的问题。)
从Linux 4.9开始,限制检查包括新管道容量所需的内存。
(2)
即使新管道容量小于现有管道容量,也要执行极限检查。如果用户设置了较大的管道​​容量,然后降低了限制,则可能导致问题,从而导致用户无法再降低管道容量。
从Linux 4.9开始,仅在增加管道容量时才执行限制检查。没有特权的用户总是可以减少管道的容量。
(3)
限制的核算和检查如下:
(a)
测试用户是否已超过限制。
(b)
进行新的管道缓冲区分配。
(c)
限制新帐户的分配。
这是比赛。多个进程可以同时通过点(a),然后分配仅在步骤(c)中说明的管道缓冲区,结果是用户的管道缓冲区分配可能超过了限制。
从Linux 4.9开始,记帐步骤在进行分配之前执行,并且如果超出限制,则操作将失败。

在Linux 4.9之前的版本中,当内核为新的管道缓冲区分配内存时,也可能会出现类似于(1)和(3)的错误。也就是说,在调用pipe(2)以及打开先前未打开的FIFO时。

另外参见

mkfifo(1),dup(2),fcntl(2),open(2),pipe(2),poll(2),select(2),socketpair(2),splice(2),stat(2), tee(2),vmsplice(2),mkfifo(3),epoll(7),fifo(7)

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/