介绍
管道可以用来两个进程之间传递数据,如ps -ef|grep “bash”,其中| 就是管道,作用就是将ps命令的结果写入管道文件,然后grep在从管道文件中读出该数据进行过滤。也就是连接一个读进程和一个写进程,以实现他们通信的一个共享文件。
管道特性:不能能在创建时就确定确定数据流向(操作系统无法确定谁读谁写),而是在使用的时候确定,因此操作系统会提供两个描述符供使用,一个读一个写,这样的确定方向就是将对应的一段关闭掉即可,这样方向的控制权就交给了用户。
相关函数介绍
pipe()
pipe函数可用于创建一个管道,以实现进程间的通信。
头文件:
函数定义:
int pipe(int fd[2]);
函数说明:
pipe函数定义中的fd参数是一个大小为2的一个数组类型的指针。该函数成功时返回0,并将一对打开的文件描述符值组填入fd参数指向的数。失败时返回 -1并设置errno。
通过pipe函数创建的这两个文件描述符fd[0] 和 fd[1] 分别构成管道的两端,往 写端文件描述符fd[1] 写入的数据可以从 读端文件描述符fd[0]读出。并且fd[1] 一端只能进行写操作,fd[0] 一端只能进行读操作,不能反过来使用,即只能实现单向传播。要实现双向数据传输,可以使用两个管道。
【阻塞与非阻塞】默认情况下,这一对文件描述符都是阻塞的。此时,如果我们用read系统调用来读取一个空的管道,则read将被阻塞,直到管道内有数据可读;如果我们用write系统调用往一个写满的管道中写数据,则write也将被阻塞,直到管道有足够的空闲空间可用(read读取数据后管道中将清除读走的数据)。当然,用户可自行将 fd[0] 和 fd[1] 设置为非阻塞的。
【不写无法读,不读无法写】如果管道的写端文件描述符 fd[1] 的引用计数减少至0,即没有任何进程需要往管道中写入数据,则对该管道的读端文件描述符 fd[0] 的read操作将返回0(管道内不存在数据的情况),即读到了文件结束标记(EOF,End Of File);反之,如果管道的读端文件描述符 fd[0] 的引用计数减少至0,即没有任何进程需要从管道读取数据,则针对该管道的写端文件描述符 fd[1] 的write操作将失败,并引发SIGPIPE信号(往读端被关闭的管道或socket连接中写数据)。
【管道自身有容量限制】管道内部传输的数据是字节流,这和TCP字节流的概念相同。但它们又存在细微的差别。应用层程序能往一个TCP连接中写入多少字节的数据,取决于对方接受窗口的大小和本端的拥塞窗口的大小。而管道的话本身拥有一个容量限制,它规定如果管道的写端应用程序不将管道中数据读走的话,该管道最多还能被写入多少字节的数据。管道容量的大小默认是65536字节。我们也可以使用fcntl函数来修改管道容量。
mkfifo()
该函数用于建立实名管道
头文件:
函数定义:
int mkfifo(const char * pathname,mode_t mode);
函数说明
mkfifo()会依参数pathname建立特殊的FIFO文件,该文件必须不存在,而参数mode为该文件的权限(mode%~umask),因此 umask值也会影响到FIFO文件的权限。mkfifo()建立的FIFO文件其他进程都可以用读写一般文件的方式存取。当使用open()来打开 FIFO文件时,O_NONBLOCK(非阻塞模式)会有影响:
1、当使用O_NONBLOCK时,打开FIFO 文件来读取的操作会立刻返回,但是若还没有其他进程打开FIFO 文件来读取,则写入的操作会返回ENXIO 错误代码。
2、没有使用O_NONBLOCK时,打开FIFO 来读取的操作会等到其他进程打开FIFO文件来写入才正常返回。同样地,打开FIFO文件来写入的操作会等到其他进程打开FIFO 文件来读取后才正常返回。
返回值
若成功则返回0,否则返回-1,错误原因存于errno中。
errno错误代码
EACCESS 参数pathname所指定的目录路径无可执行的权限
EEXIST 参数pathname所指定的文件已存在。
ENAMETOOLONG 参数pathname的路径名称太长。
ENOENT 参数pathname包含的目录不存在
ENOSPC 文件系统的剩余空间不足
ENOTDIR 参数pathname路径中的目录存在但却非真正的目录。
EROFS 参数pathname指定的文件存在于只读文件系统内。
unlink()
头文件:
#include <unistd.h>
定义函数:
int unlink(const char * pathname);
函数说明:
unlink()会删除参数 pathname 指定的文件. 如果该文件名为最后连接点, 但有其他进程打开了此文件, 则在所有关于此文件的文件描述词皆关闭后才会删除. 如果参数 pathname 为一符号连接, 则此连接会被删除。
返回值:
成功则返回0, 失败返回-1, 错误原因存于errno