有名管道(FIFO)能做什么?
引用:
2.10. 有名管道(FIFO)能做什么?
2.10.1. 什么是有名管道?
有名管道是一个能在互不相关进程之间传送数据的特殊文件。一个或多个进程向内写入数据,在另一端由一个进程负责读出。有名管道是在文件系统中可见的,也就是说ls可以直接看到。(有名管道又称FIFO,也就是先入先出。)
有名管道可以将无关的进程联系起来,而无名的普通管道一般只能将父子进程联系起来——除非你很努力地去尝试——当然也能联系两个无关进程。有名管道是严格单向的,尽管在一些系统中无名管道是双向的。
2.10.2. 我如何建立一个有名管道?
在shell下交互地建立一个有名管道,你可以用mknod或mkfifo命令。在有些系统中,mknod产生的文件可能在/etc目录下,也就是说,可能不在你的目录下出现,所以请查看你系统中的man手册。[译者注:在Linux下,可以看一下fifo(4)]
要在程序中建立一个有名管道:
/* 明确设置umask,因为你不知道谁会读写管道 */
umask(0);
if (mkfifo("test_fifo", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP))
{
perror("mkfifo");
exit(1);
}
也可以使用mknod。[译者注:在Linux下不推荐使用mknod,因为其中有许多臭虫在NFS下工作更要小心,能使用mkfifo就不要用mknod,因为mkfifo()是POSIX.1 标准。]
/* 明确设置umask,因为你不知道谁会读写管道 */
umask(0);
if (mknod("test_fifo",
S_IFIFO | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
0))
{
perror("mknod");
exit(1);
}
2.10.3. 我如何使用一个有名管道?
使用有名管道十分简单:你如同使用一个普通文件一样打开它,用read()和 write()进行操作。但对管道使用open()时可能引起阻塞,下面一些常用规律可以参考。
如果你同时用读写方式(O_RDWR)方式打开,则不会引起阻塞。
如果你用只读方式(O_RDONLY)方式打开,则open()会阻塞一直到有写方打开管道, 除非你指定了O_NONBLOCK,来保证打开成功。
同样以写方式(O_WRONLY)打开也会阻塞到有读方打开管道,不同的是如果 O_NONBLOCK被指定open()会以失败告终。
当对有名管道进行读写的时,注意点和操作普通管道和套接字时一样:当写入方关闭连接时read()返回EOF,如果没有听众write()会得到一个SIGPIPE的信号,对此信号进行屏蔽或忽略会引发一个EPIPE错误退出。
2.10.4. 能否在NFS上使用有名管道?
不能,在NFS协议中没有相关功能。(你可能可以在一个NFS文件系统中用有名管道联系两个同在客户端的进程。)
2.10.5. 能否让多个进程同时向有名管道内写入数据?
如果每次写入的数据少于PIPE_BUF的大小,那么就不会出现数据交叉的情况。但由于对写入的多少没有限制,而read()操作会读取尽可能多的数据,因此你不能知道数据到底是谁写入的。
PIPE_BUF的大小根据POSIX标准不能小于512,一些系统里在<limits.h>中被定义,[译者注:Linux中不是,其值是4096。]这可以通过pathconf()或fpathconf() 对单独管道进行咨询得到。
2.10.6. 有名管道的应用
“我如何时间服务器和多个客户端的双向交流?”
一对多的形式经常出现,只要每次客户端向服务器发出的指令小于PIPE_BUF,它们就可以通过一个有名管道向服务器发送数据。客户端可以很容易地知道服务器传发数据的管道名。
但问题在于,服务器不能用一个管道来和所有客户打交道。如果不止一个客户在读一个管道,是无法确保每个客户都得到自己对应的回复。
一个办法就是每个客户在向服务器发送信息前都建立自己的读入管道,或让服务器在得到数据后建立管道。使用客户的进程号(pid)作为管道名是一种常用的方法。客户可以先把自己的进程号告诉服务器,然后到那个以自己进程号命名的管道中读取回复。