Linux学习笔记25——命名管道(FIFO)

系统 1691 0

1 命名管道(FIFO)

      管道应用的一个重大缺陷就是没有名字,因此只能用于亲缘进程之间的通信。 后来从管道为基础提出命名管道(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           //和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文件。服务器端读取该命令并执行之。

     服务器端的代码为:

        #include <unistd.h>
        
          

#include 
        
        <stdlib.h>
        
          

#include 
        
        <stdio.h>
        
          

#include 
        
        <
        
          string
        
        .h>
        
          

#include 
        
        <unistd.h>
        
          

#include 
        
        <fcntl.h>
        
          

#include 
        
        <limits.h>
        
          

#include 
        
        <sys/types.h>
        
          

#include 
        
        <sys/stat.h>
        
          

#include 
        
        <ctype.h>




        
          #define
        
         SERVER_FIFO_NAME "/tmp/serv_fifo"


        
          #define
        
         CLIENT_FIFO_NAME "/tmp/cli_%d_fifo"


        
          #define
        
         BUFFER_SIZE 20




        
          struct
        
        
           data_to_pass_st{

    pid_t client_pid;

    
        
        
          char
        
         some_data[BUFFER_SIZE-
        
          1
        
        
          ];

};




        
        
          int
        
        
           main(){

    
        
        
          int
        
        
           server_fifo_fd,client_fifo_fd;

    
        
        
          struct
        
        
           data_to_pass_st mydata;

    
        
        
          int
        
        
           read_res;

    
        
        
          char
        
         client_fifo[
        
          256
        
        
          ];

    
        
        
          char
        
         *
        
          tmp_char_ptr;

    

    mkfifo(SERVER_FIFO_NAME,
        
        
          0777
        
        
          );

    server_fifo_fd
        
        =
        
          open(SERVER_FIFO_NAME,O_RDONLY);

    
        
        
          if
        
        (server_fifo_fd==-
        
          1
        
        
          ){

        fprintf(stderr,
        
        
          "
        
        
          Server fifo failure\n
        
        
          "
        
        
          );

        exit(EXIT_FAILURE);

    }

    sleep(
        
        
          10
        
        
          );

    
        
        
          do
        
        
          {

        read_res
        
        =read(server_fifo_fd,&mydata,
        
          sizeof
        
        
          (mydata));

        
        
        
          if
        
        (read_res>
        
          0
        
        
          ){

            tmp_char_ptr
        
        =
        
          my_data.some_data;

            
        
        
          while
        
        (*tmp_char_ptr>
        
          0
        
        
          ){

                
        
        
          //
        
        
          把some_data中的所有字符全部转换为大写
        
        

                *tmp_char_ptr=toupper(*
        
          tmp_char_ptr);

                tmp_char_ptr
        
        ++
        
          ;

            }

            sprintf(client_fifo,CLIENT_FIFO_NAME,my_data.client_pid);

            client_fifo_fd
        
        =
        
          open(client_fifo,O_WRONLY);

            
        
        
          if
        
        (client_fifo_fd!=-
        
          1
        
        
          ){

                write(client_fifo_fd,
        
        &my_data,
        
          sizeof
        
        
          (my_data));

                close(client_fifo_fd);

            }

            

        }

    }
        
        
          while
        
        (read_res>
        
          0
        
        
          );

    close(server_fifo_fd);

    unlink(SERVER_FIFO_NAME);

    exit(EXIT_SUCCESS);

}
        
      

  客户端代码为:

        #include <unistd.h>
        
          

#include 
        
        <stdlib.h>
        
          

#include 
        
        <stdio.h>
        
          

#include 
        
        <
        
          string
        
        .h>
        
          

#include 
        
        <unistd.h>
        
          

#include 
        
        <fcntl.h>
        
          

#include 
        
        <limits.h>
        
          

#include 
        
        <sys/types.h>
        
          

#include 
        
        <sys/stat.h>
        
          

#include 
        
        <ctype.h>




        
          #define
        
         SERVER_FIFO_NAME "/tmp/serv_fifo"


        
          #define
        
         CLIENT_FIFO_NAME "/tmp/cli_%d_fifo"


        
          #define
        
         BUFFER_SIZE 20




        
          struct
        
        
           data_to_pass_st{

    pid_t client_pid;

    
        
        
          char
        
         some_data[BUFFER_SIZE-
        
          1
        
        
          ];

};




        
        
          int
        
        
           main(){

    
        
        
          int
        
        
           server_fifo_fd,client_fifo_fd;

    
        
        
          struct
        
        
           data_to_pass_st my_data;

    
        
        
          int
        
        
           times_to_send;

    
        
        
          char
        
         client_fifo[
        
          256
        
        
          ];

    

    server_fifo_fd
        
        =
        
          open(SERVER_FIFO_NAME,O_WRONLY);

    
        
        
          if
        
        (server_fifo_fd==-
        
          1
        
        
          ){

        fprintf(stderr,
        
        
          "
        
        
          Sorry,no server\n
        
        
          "
        
        
          );

        exit(EXIT_FAILURE);

    }

    my_data.client_pid
        
        =
        
          getpid();

    sprintf(client_fifo,CLIENT_FIFO_NAME,my_data.client_pid);

    
        
        
          if
        
        (mkfifo(client_fifo,
        
          0777
        
        )==-
        
          1
        
        
          ){

        fprintf(stderr,
        
        
          "
        
        
          Sorry,can't make %s\n
        
        
          "
        
        
          ,client_fifo);

        exit(EXIT_FAILURE);

    }

    
        
        
          for
        
        (times_to_send=
        
          0
        
        ;times_to_send<
        
          5
        
        ;times_to_send++
        
          ){

        sprintf(my_data.some_data,
        
        
          "
        
        
          Hello from %d
        
        
          "
        
        
          ,my_data.client_pid,my_data.some_data);

        write(server_fifo_fd,
        
        &my_data,
        
          sizeof
        
        
          (my_data));

        client_fifo_fd
        
        =
        
          open(client_fifo,O_RDONLY);

        
        
        
          if
        
        (client_fifo_fd!=-
        
          1
        
        
          ){

            
        
        
          if
        
        (read(client_fifo_fd,&my_data,
        
          sizeof
        
        (my_data))>
        
          0
        
        
          ){

                printf(
        
        
          "
        
        
          received:%s\n
        
        
          "
        
        
          ,my_data.some_data);

            }

            close(client_fifo_fd);

        }

    }

    close(server_fifo_fd);

    unlink(client_fifo);

    exit(EXIT_SUCCESS);

    

}
        
      

5 总结

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

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

Linux学习笔记25——命名管道(FIFO)


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论