1 命名管道(FIFO)

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

2 命名管道的创建

  1. #include <sys/types.h>
    #include <sys/stat.h>
    int mkfifo(const char *pathname,    //文件的路径
           mode_t mode          //和open函数mode一样
          );

  如果pathname路径下的文件已经存在,则mkfifo返回-1,errono将会返回EEXIST。

3 命名管道操作

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

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

A 当以阻塞(未指定O_NONBLOCK)方式只读打开FIFO的时候,则将会被阻塞,直到有其他进程以写方式打开该FIFO。
           B 类似的,当以阻塞(未指定O_NONBLOCK)方式只写打开FIFO的时候,则将会被阻塞,直到有其他进程以读方式打开该FIFO
           C 当以非阻塞方式(指定O_NONBLOCK)方式只读打开FIFO的时候,则立即返回。当只写open时,如果没有进程为读打开FIFO,则返回-1,其errno是ENXIO

  如果写入管道的数据量小于等于PIPE_BUF,则系统保证write为原子操作,多个进程同时写管道,将不会出现穿插;如果写入数据量大于PIPE_BUF,则系统将不保证write为原子操作,多个进程同时写管道,则将有可能会穿插写入。这个规则在命名管道中继续适用。
 

4 应用实例

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

服务器端的代码为:

  1. #include <unistd.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <fcntl.h>
  7. #include <limits.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <ctype.h>
  11.  
  12. #define SERVER_FIFO_NAME "/tmp/serv_fifo"
  13. #define CLIENT_FIFO_NAME "/tmp/cli_%d_fifo"
  14. #define BUFFER_SIZE 20
  15.  
  16. struct data_to_pass_st{
  17. pid_t client_pid;
  18. char some_data[BUFFER_SIZE-];
  19. };
  20.  
  21. int main(){
  22. int server_fifo_fd,client_fifo_fd;
  23. struct data_to_pass_st mydata;
  24. int read_res;
  25. char client_fifo[];
  26. char *tmp_char_ptr;
  27.  
  28. mkfifo(SERVER_FIFO_NAME,);
  29. server_fifo_fd=open(SERVER_FIFO_NAME,O_RDONLY);
  30. if(server_fifo_fd==-){
  31. fprintf(stderr,"Server fifo failure\n");
  32. exit(EXIT_FAILURE);
  33. }
  34. sleep();
  35. do{
  36. read_res=read(server_fifo_fd,&mydata,sizeof(mydata));
  37. if(read_res>){
  38. tmp_char_ptr=my_data.some_data;
  39. while(*tmp_char_ptr>){
  40. //把some_data中的所有字符全部转换为大写
  41. *tmp_char_ptr=toupper(*tmp_char_ptr);
  42. tmp_char_ptr++;
  43. }
  44. sprintf(client_fifo,CLIENT_FIFO_NAME,my_data.client_pid);
  45. client_fifo_fd=open(client_fifo,O_WRONLY);
  46. if(client_fifo_fd!=-){
  47. write(client_fifo_fd,&my_data,sizeof(my_data));
  48. close(client_fifo_fd);
  49. }
  50.  
  51. }
  52. }while(read_res>);
  53. close(server_fifo_fd);
  54. unlink(SERVER_FIFO_NAME);
  55. exit(EXIT_SUCCESS);
  56. }

  客户端代码为:

  1. #include <unistd.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <fcntl.h>
  7. #include <limits.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <ctype.h>
  11.  
  12. #define SERVER_FIFO_NAME "/tmp/serv_fifo"
  13. #define CLIENT_FIFO_NAME "/tmp/cli_%d_fifo"
  14. #define BUFFER_SIZE 20
  15.  
  16. struct data_to_pass_st{
  17. pid_t client_pid;
  18. char some_data[BUFFER_SIZE-];
  19. };
  20.  
  21. int main(){
  22. int server_fifo_fd,client_fifo_fd;
  23. struct data_to_pass_st my_data;
  24. int times_to_send;
  25. char client_fifo[];
  26.  
  27. server_fifo_fd=open(SERVER_FIFO_NAME,O_WRONLY);
  28. if(server_fifo_fd==-){
  29. fprintf(stderr,"Sorry,no server\n");
  30. exit(EXIT_FAILURE);
  31. }
  32. my_data.client_pid=getpid();
  33. sprintf(client_fifo,CLIENT_FIFO_NAME,my_data.client_pid);
  34. if(mkfifo(client_fifo,)==-){
  35. fprintf(stderr,"Sorry,can't make %s\n",client_fifo);
  36. exit(EXIT_FAILURE);
  37. }
  38. for(times_to_send=;times_to_send<;times_to_send++){
  39. sprintf(my_data.some_data,"Hello from %d",my_data.client_pid,my_data.some_data);
  40. write(server_fifo_fd,&my_data,sizeof(my_data));
  41. client_fifo_fd=open(client_fifo,O_RDONLY);
  42. if(client_fifo_fd!=-){
  43. if(read(client_fifo_fd,&my_data,sizeof(my_data))>){
  44. printf("received:%s\n",my_data.some_data);
  45. }
  46. close(client_fifo_fd);
  47. }
  48. }
  49. close(server_fifo_fd);
  50. unlink(client_fifo);
  51. exit(EXIT_SUCCESS);
  52.  
  53. }

5 总结

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

6  FIFO的缺点
     当然FIFO也有它的局限性。客户端可以发请求到服务器,但前提是要知道一个公共的FIFO通道,对于实现服务器回传应答到客户端的问题,可以通过为每一个客户端创建一个专用的FIFO,来实现回传应答。但也有不足,服务器会同时应答成千上万个客户端,创建如此多的FIFO是否会使系统负载过大,相应的如何判断客户端是否因意外而崩溃成为难题,或者客户端不读取应答直接退出,所以服务器必须处理SIGPIPE信号,并做相应处理。(当没有进程为读打开FIFO文件时,write函数进行写操作会产生SIGPIPE信号)

Linux学习笔记25——命名管道(FIFO)的更多相关文章

  1. Linux学习笔记24——进程管道

    一 管道的作用 通常把一个进程的输出通过管道连接到另一个进程的输入. 二 popen和pclose函数 #include <stdio.h> FILE *popen(const char ...

  2. Linux学习笔记——管道PIPE

    管道:当从一个进程连接数据流到另一个进程时,使用术语管道(pipe).# include <unistd.h> int pipe(int filedes[2]); //创建管道 pipe( ...

  3. Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)

    整理自网络 Unix IPC包括:管道(pipe).命名管道(FIFO)与信号(Signal) 管道(pipe) 管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道 ...

  4. Linux 学习笔记

    Linux学习笔记 请切换web视图查看,表格比较大,方法:视图>>web板式视图 博客园不能粘贴图片吗 http://wenku.baidu.com/view/bda1c3067fd53 ...

  5. 91 Testing Linux学习笔记

    91 Testing Linux学习笔记... 学习地址:91Testing 的Linux教程=====================学习网址:http://www.91testing.net/ar ...

  6. (转)Linux最常用指令及快捷键 Linux学习笔记

    Linux最常用指令及快捷键 Linux学习笔记 原文:http://blog.csdn.net/yanghongche/article/details/50827478 [摘自 鸟叔的私房菜]--转 ...

  7. Linux学习笔记(六) 进程管理

    1.进程基础 当输入一个命令时,shell 会同时启动一个进程,这种任务与进程分离的方式是 Linux 系统上重要的概念 每个执行的任务都称为进程,在每个进程启动时,系统都会给它指定一个唯一的 ID, ...

  8. Linux学习笔记(七) 查询系统

    1.查看命令 (1)man 可以使用 man 命令名称 命令查看某个命令的详细用法,其显示的内容如下: NAME:命令名称 SYNOPSIS:语法 DESCRIPTION:说明 OPTIONS:选项 ...

  9. 进程间通信系列 之 命名管道FIFO及其应用实例

    进程间通信系列 之 概述与对比   http://blog.csdn.net/younger_china/article/details/15808685  进程间通信系列 之 共享内存及其实例   ...

随机推荐

  1. vs2015中ctrl+shift+F进行“在文件中查找”,有时候无效?

    搜狗拼音的默认简繁切换快捷键是ctrl+shift+F,改掉以后vs就可以收到这个按键消息了

  2. 15第十五章UDF用户自定义函数(转载)

    15第十五章UDF用户自定义函数 待补上 原文链接 本文由豆约翰博客备份专家远程一键发布

  3. SQL输出矩阵

    数据库环境:SQL SERVER2008R2 需求:用SQL实现如下2个图中的矩阵.            图1和图2都是行列转换的另一个变形,下面直接贴上SQL脚本. 图1的SQL实现 /*利用系统 ...

  4. CATransform3DRotate 实现左右,上下翻转效果

        CGFloat m34 = 800; CGFloat value = -40://(控制翻转角度) CGPoint point = CGPointMake(0.5, 0.5);//设定翻转时的 ...

  5. C# 匿名表达式(Lambda表达式)

    匿名表达式 这次来说说Lambda表达式吧,反正也简单,我也不像其他高手那样强调来强调去,只讲一下方法: 准备条件如下: 第一,匿名表达式必须存在与之对应的委托. 只要存在相对应的委托就可以了.接下来 ...

  6. 类库探源——System.Delegate

    一.MSDN 描述 Delegate 类:表示委托,委托是一种数据结构,它引用静态方法或引用类实例及该类的实例方法.(是不是感觉很像C语言中的函数指针 :) ) 命名空间: System 程序集:   ...

  7. COM简单应用示例

    使用com技术开发模式进行的示例. com技术关键部分源码:主要将所有接口都写入到这个文件中 testinterface.h #ifndef TESTINTERFACE_H #define TESTI ...

  8. C++ 中的权限控制

    权限控制,指的是用户只能访问符合自己权限的资源,系统对用户进行权限控制以防止用户的误操作/恶意操作等. 在C++代码中,权限控制指的是程序员在接口声明/类声明/函数声明等中进行的授权控制.如下面的代码 ...

  9. GCC选项-Xlinker和-Wl区别

    写下给自己备忘,在一次使用GCC的过程中发现了原来传递给链接器ld可以同时使用Xlinker和Wl两种命令,这两个命令都可以正确传递给ld作为使用,现在总结下两者的区别. Xlinker后面跟的参数第 ...

  10. jquery 三种开始写法

    在 jquery 代码中使用 $(document).ready()时,位于其中的所有代码都会在 DOM 加载后立即执行 第一种(推荐)$(document).ready(function(){   ...