FIFO文件 命名管道

命名管道 即FIFO文件,通过命名管道可以在不相关的进程之间交换数据。FIFO有路径名与之相关联,以一种特殊设备文件形式存在于文件系统中

FIFO有两种用途:

   (1)FIFO由shell使用以便数据从一条管道线传输到另一条,为此无需创建临时文件
   (2)FIFO用于客户进程-服务器进程程序中,已在客户进程与服务器进程之间传送数据。

FIFO的读写规则:

从FIFO中读取数据:

1.如果有进程写打开FIFO,且当前FIFO内没有数据,则对于设置了阻塞标志的读操作来说,将一直阻塞
  对于没有设置阻塞标志的读操作来说则返回-1,当前errno值为EAGAIN,提醒以后再试。

2.对于设置了阻塞标志的读操作来说,造成阻塞的原因有两种:一种是当前FIFO内有数据,但有其它进程正在读这些数据;另一种是FIFO内没有数据,阻塞原因是FIFO中有新的数据写入,而不论新写入数据量的大小,也不论读操作请求多少数据量(正在写)。

3.读打开的阻塞标志只对本进程第一个读操作施加作用,如果本进程内有多个读操作序列,则在第一个读操作被唤醒并完成读操作后其他将要执行的读操作将不再阻塞,即使在执行读操作时,FIFO中没有数据也一样(此时,读操作返回0)

4.如果没有进程写打开FIFO,则设置了阻塞标志的读操作会阻塞

5.如果FIFO中有数据,则设置了阻塞标志的读操作不会因为FIFO中的字节数小于请求读的字节数而阻塞,此时,读操作会返回FIFO中现有的数据量

向FIFO中写入数据

对于设置了阻塞标志的写操作:

1.当要写入的数据量不大于PIPE_BUF时,Linux将保证写入的原子性。如果此时管道空闲缓冲区不足以容纳要写入的字节数,则进入睡眠,知道当缓冲区中能够容纳要写入的字节数时,才开始进行一次性写操作。

2.当要写入的数据量大于PIPE_BUF时,Linux将不再保证写入的原子性。FIFO缓冲区一有空闲区域,写进程就会试图向管道写入数据,写操作在写完所有请求写的数据后返回。

对于没有设置阻塞标志的写操作

1.当要写入的数据量大于PIPE_BUF时,Linux将不再保证写入的原子性。再写满所有FIFO空闲缓冲区后,写操作返回。

2.当要写入的数据量不大于PIPE_BUF时,Linux将保证写入的原子性。如果当前FIFO空闲缓冲区能够容纳请求写入的字节数,写完后成功返回;如果当前FIFO空闲缓冲区不能够容纳请求写入的字节数,则返回EAGAIN错误,提醒以后再写。

FIFO的一些注意问题: 

(1)管道数据的FIFO处理方式 

      先放入管道的数据,在端口首先被读出 

(2)管道数据的不可再现性 

      已读取的数据在管道里消失,不能再读 

(3)管道长度的有限性 

(4)SIGPIPE信号 如果一个进程试图写入到一个没有读取进程的管道中,系统内核产生SIGPIPE信号 

实例1 :

#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<fcntl.h>
#include<string.h>
#define FIFO "/tmp/my_fifo"
main(int argc,char ** argv){
   char buf_r[100];
   int fd;
   int nread;
   if((mkfifo(FIFO,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST))     //O_EXCL:可执行
     printf("cannot create FIFOserver\n");
   printf("Preparing for reading bytes...\n");
   memset(buf_r,0,sizeof(buf_r));
   fd=open(FIFO,O_RDONLY|O_NONBLOCK,0);  //O_RDONLY:只读,O_NONBLOCK:非阻塞
   if(fd==-1){
     perror("open");
     exit(1);
   }
   while(1){
     memset(buf_r,0,sizeof(buf_r));
     if((nread=read(fd,buf_r,100))==-1){
       if(errno==EAGAIN)
         printf("no data yet\n");
     }
     printf("read %s from FIFO\n",buf_r);
     sleep(1);
   }
   pause();
   unlink(FIFO);
}

扫描二维码关注公众号,回复: 6613291 查看本文章

实例2 :

分别写两个程序,一个是服务器程序,不断从管道读取客户发送的信息;
另一个是客户程序,在命令行输入信息并从管道发送: 

客户程序(写管道) 

  1. /*fifo_write.c*/
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <errno.h>
  5. #include <fcntl.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. /*FIFO管道路径*/
  10. #define FIFO_SERVER "/tmp/myfifo"
  11. main(int argc,char** argv)  
  12. {  
  13. int fd = 0;  
  14. char w_buf[100];  
  15. int nwrite;  
  16. /*打开FIFO管道*/
  17.    fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0);  
  18. if(fd==-1)  
  19. if(errno==ENXIO)  
  20.        printf("open error; no reading process\n");  
  21. /*判断有没有参数输入*/
  22. if(argc==1)  
  23.      printf("Please send something\n");  
  24. /*复制参数输入*/
  25.    strcpy(w_buf,argv[1]);  
  26. /*写到FIFO去*/
  27. if((nwrite=write(fd,w_buf,100))==-1)  
  28.    {  
  29. if(errno==EAGAIN)  
  30.        printf("The FIFO has not been read yet.Please try later\n");  
  31.    }  
  32. else
  33. /*输出写入的内容*/
  34.      printf("write %s to the FIFO\n",w_buf);  
  35. }  

服务程序(读管道) 

  /*fifo_read.c*/

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <errno.h>
  4. #include <fcntl.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. /*定义FIFO路径*/
  9. #define FIFO "/tmp/myfifo"
  10. main(int argc,char** argv)  
  11. {  
  12. char buf_r[100];  
  13. int  fd;  
  14. int  nread;  
  15. /*创建FIFO管道*/
  16. if((mkfifo(FIFO,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST))  
  17.      printf("cannot create fifoserver\n");  
  18. printf("Preparing for reading bytes...\n");  
  19. memset(buf_r,0,sizeof(buf_r));  
  20. /*打开FIFO管道,不阻塞方式*/
  21.    fd=open(FIFO,O_RDONLY|O_NONBLOCK,0);  
  22. if(fd==-1)  
  23.    {  
  24.      perror("open");  
  25.      exit(1);    
  26.    }  
  27. while(1)  
  28.    {  
  29.      memset(buf_r,0,sizeof(buf_r));  
  30. /*读管道,因为定义了非阻塞方式,故在此不会阻塞进程*/
  31.      if((nread=read(fd,buf_r,100))==-1){  
  32.         if(errno==EAGAIN)  printf("no data yet\n");  
  33.      }  
  34.      printf("read %s from FIFO\n",buf_r);  
  35.      sleep(1);  
  36.    }    
  37.    pause();  
  38.    unlink(FIFO);  
  39. }  
  40.  

接下来进行编译,编译好后,在Linux中运行两个终端,分别运行以上两个程序,可以看到,运行fifo_read时,程序一直在每隔一秒读,然后我们在另一个终端输入: 

$ ./fifo_write helloworld

可以看出fifo_read显示出helloworld”,说明接受成功 

下接下来进行编译,编译好后,在Linux中运行两个终端,分别运行以上两个程序,可以看到,运行fifo_read时,程序一直在每隔一秒读,然后我们在另一个终端输入: 

$ ./fifo_write helloworld

可以看出fifo_read显示出helloworld”,说明接受成功

 

猜你喜欢

转载自blog.csdn.net/qq_38971487/article/details/91493102