1、管道
pipe函数创建单向数据流
#include <unistd.h>
int pipe(int fd[2]);
成功返回0,失败返回-1
该函数返回两个文件描述字:fd[0]和fd[1],fd[0]打开来读,fd[1]打开来写
用途时提供两个不同进程(一个是父进程,一个是子进程)间的通信手段。首先,由一个进程(父进程)创建一个管道后调用fork派生一个自身的拷贝
2、popen和pclose
popen创建一个管道并启动另外一个进程,该进程或者从该管道中读出标准输入,或者往该管道写入标准输出
#include <stdio.h>
FILE *popen(const char *command, const char *type);
成功返回文件指针,失败返回NULL
int pclose(FILE *stream);
成功返回shell的终止状态,失败返回-1
command是shell命令行。popen在调用进程和所指定的命令之间创建一个管道。由popen返回的值是一个标准I/O FILE指针,该指针或者用于输入,或者用于输出,具体取决于字符串type
如果type为r,调用进程读进command的标准输出
如果type为w,调用进程写到command的标准输入
3、FIFO
无亲缘关系的进程可以用它创建彼此间的管道。是一个单向(半双工)数据流,每个FIFO有一个路径名与之关联,也称作有名管道。FIFO用mkfifio函数创建,其函数原型为
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
成功返回0,失败返回-1
pathname是一个普通的Unix路径名,它是该FIFO的名字
mode参数指定文件权限位,类似于open的第三个参数。定义在<sys/stat.h>头文件中的用于给一个FIFO指定权限位的6个常值
mkfifo函数已隐含指定O_CREAT|O_EXCL。也就是说,它要么创建一个新的FIFO,要么返回一个EEXIST错误。如果不希望创建一个新的FIFO,就改为open。
FIFO不能打开既读又写,因为它是半双工的。对管道或FIFO的write总是往末尾添加数据,read则总是从开头返回数据,如果对管道或FIFO调用lseek,返回ESPIPE错误
管道在将它打开着的进程中最后一个关闭它之后自动消失,FIFO的名字只有通过调用 unlink才从文件系统中删除
使用FIFO的顺序很微妙,如果当前尚没有任何进程打开某个FIFO来写,那么打开该FIFO来读的进程将阻塞
4、管道和FIFO的额外属性
设置非阻塞方式的两种方式
(1)调用open指定O_NONBLOCK标志
(2)如果描述字已经打开,调用fcntl使能O_NONBLOCK
非阻塞标志对于打开一个FIFO的影响、对于从一个空管道或空FIFO读出数据的影响以及对于往一个管道或FIFO写入数据的影响:
读出或写入的几个规则:
(1)如果请求读出的数据量多于管道或FIFO中当前可用数据量,只返回这些可用的数据。但是必须处理来自read的小于所请求数目的返回值
(2)如果请求写入的数据的字节数小于或等于PIPE_BUF,那么write操作保证是原子的。如果请求写入的字节数大于PIPE_BUF,那么write操作不能保证是原子 的
(3)O_NONBLOCK标志的设置对于write的原子操作没有影响--原子性操作完全是由所请求字节数是否小于等于PIPE_BUF决定的。然而当一个管道或FIFO设置成非阻塞时,来自write的返回值取决于待写的字节数以及该管道或FIFO中当前可有空间的大小。
如果待写的字节数小于等于PIPE_BUF:
(a)如果管道或FIFO中有足以存放请求字节数据的空间,那么所有数据字节都写入
(b)如果管道或FIFO中没有足以存放所请求字节数的空间,那么立即返回一个EAGAIN错误
如果待写的字节数大于PIPE_BUF:
(a)如果管道或FIFO中至少有一个字节空间,内核写入能容纳的数据字节,该数目同时作为来来自write的返回值
(b)如果管道或FIFO已满,立即返回EAGAIN错误
如果写入一个没有打开着用于读的管道或FIFO,将产生一个SIGPIPE信号
(a)如果调用进程既没有捕获也没有忽略SIGPIPE信号,缺省行为是终止该进程
(b)如果进程忽略SIGPIPE信号或捕获该信号并从信号处理程序返回,write返回一个EPIPE错误
5、管道和FIFO限制
加于管道和FIFO的唯一限制:
OPEN_MAX:一个进程在任意进户可以打开的最大描述字
PIPE_BUF:可原子地写往一个管道或FIFO的最大数据量