1、管道及命名管道
管道是linux 提供的最早的进程通信
方式之一,是Linux中重要的通信方式,有
无名管道和命名管道(也可以称为有名管
道)两种,是把一个程序的输出直接连接
到另一个程序的输入。常说的管道多指无
名管道,无名管道只能用于具有亲缘关系
的进程之间,并且只能用于单向通信,如
果要实现进程间的双向通信则需要使用两
个无名管道,而命名管道则没有这方面的
限制,如下图。命名管道是一个能在无亲
缘关系的进程之间传送数据的特殊文件,
用fifo来表示。一个或多个进程在一端写
入数据,在另一端由一个进程负责读出。
图 1 无名管道与命名管道对比
2、命名管道的打开及读写规则
2.1 打开规则
命名管道的打开规则比较复杂,重要
原因是open系统调用具有是否阻塞的选项
O_NONBLACK。打开规则如表1所示。
2.2 读写规则
对一个空的,阻塞的命名管道的read
调用将等待,直到有数据可以读时才能继
续执行,与此相反,对一个空的,非阻
塞的fifo的read调用将立刻返回0字节。
对于阻塞的命名管道的write调用将等
待,直到数据可以被写入时才继续执行。
如果请求写入的数据的长度小于等于
PIPE_BUF 的长度,调用失败。
如果请求写入的数据的长度大于
PIPE_BUF字节,将写入部分数据,返回
实际写入的字节数,返回值也可能是0。
3、命名管道通信相关的系统调用
3.1 mkfifo系统调用
#include
#include
int mkfifo(const char * pathname,
mode_t mode);
该系统调用使用指定的文件名创建
fifo。第一个参数是一个路径名,也就是
创建命名管道的位置。第二个参数与open
()函数中的mode 参数相同。如果mkfifo
的第一个参数是一个已经存在的路径名
时,会返回EEXIST错误,所以典型的调
用代码会首先检查,如果返回该错误,那
么直接使用命名管道即可。
3.2 命名管道的读写
#include
ssize_t read(int fd, void
*buf, size_t
count);
ssize_t write(int fd, const void *buf,
size_t count);
read系统调用将从fd所指向的文件读
出count字节的数据并存入buf指向的数据
区里面,如果执行成功,返回实际读入的
字节数,可能会小于count;执行出错,返
回 - 1。返回 0 表示到达了文件尾。
write系统调用将buf指向的数据区里
面的count字节的数据写入到文件描述符
fd指向的文件里面,返回实际写入的字节
数。如果返回0,表示未写入任何数据。
如果返回 - 1,表示执行出错。
此外,用于一般文件的I/O函数都可
以用于FIFO文件,不再详细介绍,读者可
参考相关文献。
4、实例分析
我们通过两个进程来分析命名管道在
进程通信中的使用,其中一个进程向命名
管道中写入数据,另外一个进程从命名管
道中读取数据。
4.1 读进程(fifor.c)
读进程的代码,篇幅的关系省略了头
文件 :
#def ine f i fo_name "/home/
fifoserver"
int main(){
int fifo_fd;
int num;
char buf[1024];
if (access(fifo_name, F_OK)== -1){
fifo_fd = mkfifo(fifo_name, 0777);
}
printf("process %d opening fifo for
read\n", getpid());
f i f o _ f d = o p e n ( f i f o _ n am e
,
O_RDONLY);
printf("process %d open for read result
%d \n", getpid(), fifo_fd);
num=read(fifo_fd,buf,1024);
printf("process %d read down\n",
getpid());
printf("data read from fifo is: %s\n",
buf);
(void)close(fifo_fd);
exit(0);
}
gcc fifor.c -o fir
4.2 写进程(fifow.c)
#def ine f i fo_name "/home/
fifoserver"
int main(){
int fifo_fd;
int num;
char buf[1024];
printf("please input char;\n");
fgets(buf,1024,stdin);
if (access(fifo_name,F_OK)== -1){
fifo_fd=mkfifo(fifo_name, 0777);
}
printf("process %d opening fifo for
write \n", getpid());
f i f o _ f d = o p e n ( f i f o _ n a m e ,
O_WRONLY);
printf("process %d open for write
result %d \n", getpid(), fifo_fd);
num=write(fifo_fd, buf, 1024);
printf("process %d write down\n",
getpid());
printf("data write into fifo is :%s\n",
buf);
(void)close(fifo_fd);
exit(0);
}
gcc fifow.c -o fiw
5、运行结果及分析
分析运行结果我们可以看到,当我们输入一段字符到buf之后,首先后
台运行管道写进程fifow, fifow试图为了写
数据而打开管道,此时打印出“process
2884 opening fifo for write”,但是因
为没有进程读打开该管道,所以写进程会
阻塞而不是继续运行,写进程会一直阻塞
到fifor进程读打开命名管道fifoserver。然
后,我们前台运行读进程f i for,读进程
会试图读打开fifo,此时在屏幕上打印出
“process 2900 opening fifo for read”,
在读进程打开命名管道后,写进程继续运
行。 然后, 写进程向管道中写入数据, 写入
的数据会被读进程读出,然后打印在屏幕
上。