Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1798373
  • 博文数量: 438
  • 博客积分: 9799
  • 博客等级: 中将
  • 技术积分: 6092
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-25 17:25
文章分类

全部博文(438)

文章存档

2019年(1)

2013年(8)

2012年(429)

分类: 系统运维

2012-04-02 16:57:41

FIFO通常被称为命名管道。管道只能在有共同祖先创建管道时的相关进程间使用。(一个例外是挂载的基于STREAM的管道,17.2.2节。)然而,有了FIFO,不相关的进程也可以交换数据。


我们在第4章看到FIFO是一个文件类型。stat结构体(4.2节)的st_mode成员的某个编码指明一个文件是FIFO。我们可以用S_ISFIFO宏来测试这个。


创建一个FIFO和创建一个文件相似。事实上,FIFO的路径名存在于文件系统里的。



  1. #include <sys/stat.h>

  2. int mkfifo(const char *pathname, mode_t mode);

  3. 成功返回0,错误返回-1。


mkfifo函数的mode参数的规定和open函数(3.3节)相同。新FIFO的用户和组的所属关系的规则和4.6节描述的一样。


一旦我们使用了mkfifo来创建一个FIFO,我们使用open来打开它。事实上,普通的文件I/O函数(close、read、write、unlink等)都能工作在FIFO上。


应用可以用mknod函数创建FIFO。因为POSIX.1最开始并没有包含mknod,所以mkfifo为POSIX.1特意发明。mknod函数现在包含在XSI扩展里。在多数系统上,mkfifo调用mknod来创建FIFO。


POSIX.1也包含mkfifo命令的支持。本文四个平台都提供了这个命令。这允许一个FIFO使用一个外壳命令被创建,然后用普通外壳I/O重定向访问。


当我们open一个FIFO时,非阻塞标志(O_NONBLOCK)影响了发生的事情。


1、在通常情况下(O_NONBLOCK没有被指定),一个只读的open阻塞,直到一些其它进程打开FIFO来写。相似的,只写的open阻塞,直到一些其它进程打开FIFO来读。


2、如果O_NONBLOCK被指定,一个只读的open立即返回。但是只写的open返回-1,errno设为ENXIO,如果没有进程打开FIFO来读。


和一个管道一样,如果我们write到一个没有进程打开来读的FIFO,那么信号SIGPIPE被产生。当FIFO的最后写者关闭了FIFO,一个文件末尾为FIFO的读者产生。


对一个给定的FIFO有多个写者是普遍的。这意味着我们必须担心原子写,如果我们不想多个进程的写交叉。(我们将在17.2.2节看到解决这个问题的一种方法。)和管道一样,常量PIPE_BUF指定了可以被原子写到FIFO的最大数据量。


FIFO有两种用法:


1、FIFO被外壳命令用来传递数据,从一个外壳管道到另一个,而不需要创建中间的临时文件。


2、FIFO被用来在客户-服务器应用里作为集结点来在客户端和服务器端之间传送数据。


我们为每种使用提供一个例子。


FIFO可以被用来在一个外壳命令序列里复制一个输出流。这避免了向一个临时磁盘文件写数据(和使用管道来避免中间磁盘文件是相似的)。但是管道只能被用来在进程间进程线性连接,而FIFO有一个名字,所以它可以用在非线性连接上。


考虑一个需要处理一个过滤好的输入流两次的过程。程序prog1读取输入文件,把输出同时发送到程序prog2和prog3。


使用FIFO和UNIX系统tee,我们可以完成这个过程,而不需要一个临时文件。(tee程序把它的标准输入同时拷贝到它的标准输出和在它命令行命名的文件里。)


mkfifo fifo1
prog3 < fifo1 &
prog1 < infile | tee fifo1 | prog2


我们创建FIFO然后在后台启动prog3,从FIFO读取。我们然后启动prog1并使用tee来把它的输入同时发送给FIFO和prog2。(在我们Linux3.0上,这种方式有时不工作,因为FIFO的读者有时收不到写者发出的数据,而有时也能收到。)


FIFO 的另一个使用是在客户端和服务器端之间发送数据。如果我们有一个服务器,它被许多客户联系,每个客户可以把它的请求写到一个由服务器创建的被熟知的 FIFO。(“被熟知的”的意思是FIFO的路径名被所有需要和服务器联系的客户端所知道。)服务器创建一个FIFO并从中读取读取,多个客户端向这个 FIFO写入请求。因为FIFO有多个写者,客户端发送给服务器的请求应该比PIPE_BUF字节少。这避免了任何客户write的交叉。


使 用FIFO作为这种类型的客户-服务器通信的问题是如何从服务器发回回复给每个子进程。单个FIFO不能被使用,因为客户端不会知道何时去读它们的响应, 与其它客户端的响应相对。一种解决方案是每个客户端随着请求发送它的进程ID。服务器然后为每个客户端创建一个唯一的FIFO,使用基于客户端进程ID的 路径名。例如,服务器可以创建一个FIFO,名字为/tmp/serv1.XXXX,这里XXXX被客户端的进程ID代替。


这种方式可以工 作,尽管服务器不可能知道一个客户端是否崩溃。这导致客户相关的FIFO被留在文件系统里。服务器也必须捕获SIGPIPE,因为发送一个请求的客户端可 能在读响应之前终止,导致客户端相关的FIFO有一个写者(服务器)却没有读者。我们将看到更智能的解决这个问题的谅地,当在17.2.2节讨论挂载的基 于STREAMS的管道时。


有了上面的解决方案,如果服务器在每次客户端数从1变为0时以只读方式打开它的被熟知的FIFO(因为只从 FIFO里read),那么服务器为在FIFO上read到一个文件末尾。为了避免服务器必须处理这种情况,一个普遍的诡计只是让服务器以读写方式 open它的被熟知的FIFO。

阅读(928) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~