Chinaunix首页 | 论坛 | 博客
  • 博客访问: 289793
  • 博文数量: 186
  • 博客积分: 1531
  • 博客等级: 上尉
  • 技术积分: 1275
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-06 16:56
文章分类

全部博文(186)

文章存档

2013年(2)

2012年(184)

分类:

2012-11-20 13:30:49

1. 命名管道: FIFO
命名管道是一种特殊类型的文件,
它在文件系统中以文件名的形式存在,但它的行为却和匿名管道类似;


2. FIFO文件与普通文件之间的区别:
A. 程序不能以O_RDWR模式打开FIFO文件进行读写操作,
   这样做的后果并未明确定义,
   如果一个管道以读/写方式打开, 进程就会从这个管道读回它自己的输出.

   如果需要在程序之间双向传递数据,
   最好是使用一对FIFO或管道,一个方向使用一个;
   或者(但不常用),采用先关闭再重新打开FIFO的方法来明确改变数据流的方向.

B. 对open_flag(open函数的第二个参数)的"O_NONBLOCK"选项的用法;


3. open_flag标志(O_RDONLY, O_WRONLY和O_NONBLOCK)的4种合法组合方式:
A. 阻塞方式读open

  1. open(const char *path, O_RDONLY);
   在这种方式下,open调用将阻塞,
   除非有一个进程以写的方式打开同一个FIFO,
   否则它不会返回。

B. 非阻塞方式读open

  1. open(const char *path, O_RDONLY | O_NONBLOCK);
   即使没有其它的进程以写的方式打开FIFO,
   这个open调用也将成功并立即返回。

C. 阻塞方式写open

  1. open(const char *path, O_WRONLY);
   在这种情况下,open调用将阻塞,
   直到有一个进程以读方式打开同一个FIFO为止。

D. 非阻塞方式写open

  1. open(const char *path, O_WRONLY | O_NONBLOCK);
   这个函数调用总是立即返回,
   如果 没有进程以读方式打开FIFO文件,
        open调用将返回一个错误-1并且FIFO也不会打开。
   
   如果 有一个进程以读方式打开FIFO文件,
        那么可以通过这个函数返回的文件描述符对这个FIFO进行写操作。

close调用行为并不受O_NONBLOCK标志的影响.


open模式的最常见的组合形式:
A. 阻塞方式读open + 阻塞方式写open
   这样的形式, 它允许先启动读进程,并在open调用中等待,
   当写进程打开FIFO时,
   两个进程在open调用处取得同步,两个程序继续运行。

B. 非阻塞方式读open + 阻塞方式写open
   这时,读进程在即使没有写进程存在的情况下,仍能执行open调用并继续执行.
   随后写进程开始执行,
   因为FIFO已被读进程打开,它在open调用后立即继续执行.
  

4. 使用O_NONBLOCK对FIFO的read和write操作约定:
对一个空的,阻塞的FIFO(即没有用O_NONBLOCK标志打开)的read调用将等待,
直到有数据可以读时才执行。

与此相反,
对一个空的,非阻塞的FIFO的read调用立即返回0字节。

对一个完全阻塞FIFO的write调用将等待,
直到数据可以被写入时才继续执行。

如果FIFO不能接收所有写入的数据,它将按下面的规则执行:
  如果 请求写入的数据长度 <= PIPE_BUF字节
       调用失败,数据不能写入。

  如果 请求写放的数据长度 >  PIPE_BUF字节
       将写入部分数据,返回实际写入的字节数,返回值也可能是0.

FIFO的长度定义在limits.h中的
#define PIPE_BUG语句中定义,
linux下的值通常是4096字节。

FIFO的原子性:
系统规定, 在一个以O_WRONLY方式打开的FIFO中,
如果写入的数据长度 <= PIPE_BUF字节,
那么或者写入全部字节,或者一个字节都不写入。

如果保证所有写请求是发往一个阻塞的FIFO的,
并且每个写请求的数据长度 <= PIPE_BUF字节,
系统将会保证数据决不会交错在一起。
所以,通常将每次通过FIFO传递的数据长度限制为PIPE_BUF字节是个好方法。

5. 示例, 生产者--消费者模型
阻塞方式读open + 阻塞方式写open;
写进程读取文件数据并发送到FIFO;
读进程读取FIFO中的数据并显示;

代码如下:
producer.c

  1. /*
  2.  * \File
  3.  * producer.c
  4.  *
  5.  */

  6. #include <unistd.h>
  7. #include <stdlib.h>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <fcntl.h>
  11. #include <limits.h>
  12. #include <sys/types.h>
  13. #include <sys/stat.h>

  14. #define FIFO_NAME "test_fifo"
  15. #define BUFFER_SIZE (512)

  16. #define TESTF_IN "test.dat"
  17. #define OP_LEN (100)

  18. FILE* fp_in;

  19. int main(char argc, char* argv[])
  20. {
  21.     int pipe_fd;
  22.     int res;
  23.     int open_mode = O_WRONLY;
  24.     int bytes_sent = 0;
  25.     int bytes_read = 0;
  26.     char buffer[BUFFER_SIZE + 1];

  27.     if (access(FIFO_NAME, F_OK) == -1)
  28.     {
  29.         res = mkfifo(FIFO_NAME, 0777);
  30.         if (res != 0)
  31.         {
  32.             fprintf(stderr, "Could not create fifo %s\n", FIFO_NAME);
  33.             exit(EXIT_FAILURE);
  34.         }
  35.     }

  36.     printf("Process %d opening FIFO O_WRONLY\n", getpid());
  37.     pipe_fd = open(FIFO_NAME, open_mode);
  38.     printf("Process %d result %d\n", getpid(), pipe_fd);


  39.     if (pipe_fd != -1)
  40.     {

  41.         if ((fp_in = fopen(TESTF_IN, "r")) < 0)
  42.         {
  43.          fprintf(stderr, "Open input file failed:%s\n", TESTF_IN);
  44.             exit(EXIT_FAILURE);
  45.         }

  46.         while ((bytes_read = fread(buffer, sizeof(char), OP_LEN, fp_in)))
  47.         {
  48.             printf("PRODUCE: %d, %s", bytes_read, buffer);

  49.             res = write(pipe_fd, buffer, bytes_read);
  50.             if (res == -1)
  51.             {
  52.                 fprintf(stderr, "Write error on pipe\n");
  53.                 exit(EXIT_FAILURE);
  54.             }    
  55.             bytes_sent += res;        

  56.             memset(buffer, 0, BUFFER_SIZE);
  57.             if (feof(fp_in) != 0)
  58.             {
  59.                 printf("read over\n");
  60.                 break;
  61.             }
  62.         }

  63.         (void)close(pipe_fd);
  64.         fclose(fp_in);
  65.     }
  66.     else
  67.     {
  68.         exit(EXIT_FAILURE);
  69.     }

  70.     return 0;
  71. }

consumer.c

  1. /*
  2.  * \File
  3.  * consumer.c
  4.  *
  5.  */


  6. #include <unistd.h>
  7. #include <stdlib.h>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <fcntl.h>
  11. #include <limits.h>
  12. #include <sys/types.h>
  13. #include <sys/stat.h>


  14. #define FIFO_NAME "test_fifo"
  15. #define BUFFER_SIZE (512)
  16. #define OP_LEN (100)

  17. int main(char argc, char* argv[])
  18. {
  19.     int pipe_fd;
  20.     int res;
  21.     int open_mode = O_RDONLY;
  22.     char buffer[BUFFER_SIZE + 1];
  23.     int bytes_read = 0;

  24.     memset(buffer, '\0', sizeof(buffer));

  25.     printf("Process %d opening FIFO O_RDONLY\n", getpid());
  26.     pipe_fd = open(FIFO_NAME, open_mode);
  27.     printf("Process %d result %d\n", getpid(), pipe_fd);

  28.     if (pipe_fd != -1)
  29.     {
  30.         do
  31.         {
  32.             res = read(pipe_fd, buffer, OP_LEN);
  33.             printf("CONSUME: %d, %s\n", res, buffer);
  34.             bytes_read += res;

  35.             memset(buffer, 0, BUFFER_SIZE);

  36.             if (res < OP_LEN)
  37.             {
  38.                 printf("read over\n");
  39.                 break;
  40.             }
  41.         } while (res > 0);
  42.         (void)close(pipe_fd);
  43.     }
  44.     else
  45.     {
  46.         exit(EXIT_FAILURE);
  47.     }

  48.     printf("Process %d finished, %d bytes read\n", getpid(), bytes_read);
  49.     exit(EXIT_SUCCESS);
  50.     return 0;
  51. }

gcc
  1. $ gcc -o producer producer.c
  2. $ gcc -o consumer consumer.c
测试通过;
阅读(504) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~