Linux进程间通信(IPC)之二——命名管道(FIFO)

来源:互联网 发布:管家婆软件下载 编辑:程序博客网 时间:2024/06/08 10:16
1 命名管道(FIFO)

      经过前文《Linux进程间通信(IPC)之一——管道》介绍管道,但是管道应用的一个重大缺陷就是没有名字,因此只能用于亲缘进程之间的通信。后来从管道为基础提出命名管道(named pipe,FIFO)的概念,该限制得到了克服。FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,通过FIFO不相关的进程也能交换数据。值得注意的是,FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()等文件定位操作。

2 命名管道的创建

#include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode);
     该函数经创建一个FIFO,FIFO在文件系统中表现为一个文件(该文件为fifo类型文件),文件的路径由参数pathname指定;第二个参数mode和系统调用open函数中的mode是一样的如果pathname路径下的文件已经存在,则mkfifo返回-1,errono将会返回EEXIST。

3 命名管道操作

     FIFO在文件系统中表现为一个文件,大部分的系统文件调用都可以用在FIFO上面,比如:read,open,write,close,unlink,stat等函数。但是seek等函数不能对FIFO调用。

    可以调用open打开FIFO,请注意以下方面:

1、当以阻塞(未指定O_NONBLOCK)方式只读打开FIFO的时候,则将会被阻塞,直到有其他进程以写方式打开该FIFO。

2、类似的,当以阻塞(未指定O_NONBLOCK)方式只写打开FIFO的时候,则将会被阻塞,直到有其他进程以读方式打开该FIFO。

3、当以非阻塞方式(指定O_NONBLOCK)方式只读打开FIFO的时候,则立即返回。当只写open时,如果没有进程为读打开FIFO,则返回-1,其errno是ENXIO

    在上文Linux进程间通信(IPC)之一——管道》提到:如果写入管道的数据量小于等于PIPE_BUF,则系统保证write为原子操作,多个进程同时写管道,将不会出现穿插;如果写入数据量大于PIPE_BUF,则系统将不保证write为原子操作,多个进程同时写管道,则将有可能会穿插写入。这个规则在命名管道中继续适用。

4 应用实例

     本例为一个client-server模式,服务器端将会创建一个闻名fifo文件(本例中为“/tmp/server”),并读取该fifo文件。客户端则打开该fifo文件,并把其请求写入该FIFO文件。服务器端读取该命令并执行之。

     服务器端的代码为:

#include <stdio.h> 
#include <errno.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <unistd.h> 
struct fifo_cmd 
        pid_t child_pid; 
    char cmd[100]; 
}; 
int main(void
     int fd; 
       struct fifo_cmd cmd; int err; int n; 
    if((err = mkfifo("/tmp/server", 0777)) < 0) 
      if(errno != EEXIST) 
                perror("mkfido fail: ") 
                    exit(-1); 
             
  
   if((fd = open("/tmp/server", O_RDONLY)) < 0) 
       
          perror("open fail: "); 
                exit(-1); 
     
   while(1) 
      
           if((n = read(fd, &cmd, sizeof(cmd))) < 0) 
                 
                  perror("read fail: "); 
                        exit(-1); 
             
           if(n > 0) 
              {
                     printf("command from %d: %s\n", cmd.child_pid, cmd.cmd); 
          
          sleep(1); 
  }
 }

请把这个代码编译成server。

     客户端代码如下:

#include <stdio.h> 
#include <errno.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <string.h> 
struct fifo_cmd 
 pid_t pid; 
 char cmd[100]; 
}; 
int main(int argc, char* argv[]) 
   int fd; 
   struct fifo_cmd cmd; 
  if((fd = open("/tmp/server", O_WRONLY)) < 0) 
  { 
    perror("open fail: "); 
    exit(-1); 
   
  cmd.pid = getpid(); 
  while(1) 
  { 
     printf("%%: "); 
     fgets(cmd.cmd, sizeof(cmd.cmd), stdin); 
   cmd.cmd[strlen(cmd.cmd) - 1] = 0;
       if(write(fd, &cmd, sizeof(cmd)) < 0) 
       
          perror("write fail: ");
         exit(-1); 
      
   
}

请把客户端代码编译成client。

     测试时我们可以启动多个client,我们将会看到client发生命令将会在服务器端执行之。

5 总结

     与管道相比,FIFO最大的特点就是其在文件系统中有fifo文件存在,这样就可以做到进程间通信。

 FIFO的缺点
     当然FIFO也有它的局限性。客户端可以发请求到服务器,但前提是要知道一个公共的FIFO通道,对于实现服务器回传应答到客户端的问题,可以通过为每一个客户端创建一个专用的FIFO,来实现回传应答。但也有不足,服务器会同时应答成千上万个客户端,创建如此多的FIFO是否会使系统负载过大,相应的如何判断客户端是否因

0 0