Linux 进程通信,System V 第二节------> FIFO—转

一、

一些简单理解:

我们知道管道是没有标志的,所以只能是在同一个进程组中进行通信,不同的祖先产生的进程之间是不可以的!!所以此处引入FIFO机制

同样也只能是单流的!不同的是FIFO是有标志的!每个FIFO都有一个路径名与之相关!

FIFO也称为 “有名管道”

#include <sys/types.h>

#include <sys/stat.h>

int mkfifo( const char* pathname, mode_t mode );

mode 与 open函数中的一样,默认为:O_CREAT | O_EXCL

if FIFO 已经存在,那么返回EEXIST错误!if不存在那么就是创建新的FIFO。if仅仅是打开FIFO,那么就可以使用open()函数就可以了!

对于一个已经创建好的FIFO来说,只能是读或者写,不能同时进行。( 半双工 )

对于FIFO来说:先进先出,所以从开头读,从尾部写

查看所创建的管道:

ls -lF /tmp/my_fifo

> prwxr-xr-x 1 pt gf 0 2012-01-13 10:43/tmp/my_fifo|

注意:ls命令的输出结果中的第一个字符为p,表示这是一个管道。最后的|符号是由ls命令的-F选项添加的,它也表示是这是一个管道。

二、

 1 #include<stdio.h>  
 2 
 3 #include<stdlib.h> 
 4 #include<sys/types.h> 
 5 #include<sys/stat.h> 
 6     
 7 int main() 
 8 { 
 9       intres;
10   
11       if ( ( res =mkfifo("/tmp/my_fifo", 0777) ) == 0 )       //!> 对于mkfifo来说:成功则返回0,否则返回-1
12      {                                                 //!>注意全名就是   /tmp/my_fifo 其实就是tmp路径下的 my_fifo 文件
13         printf("FIFOcreated\n"); 
14      } 
15  
16      return0;
17     //!> exit(EXIT_SUCCESS);
18 }

三、

1.简介:

两个独立的程序:

1). 生产者程序,它在需要时创建管道,然后尽可能快地向管道中写入数据。

2). 消费者程序,它从FIFO中读取数据并丢弃它们。

2.代码:

 1  #include <stdio.h>
 2  #include <stdlib.h>
 3  #include <string.h>
 4  #include <fcntl.h>
 5  #include <limits.h>
 6  #include <sys/types.h>
 7  #include <sys/stat.h>
 8  
 9  #define FIFO_NAME   "/tmp/Linux/my_fifo"            //!> FIFO全名
10  #define  BUFFER_SIZE 40                              //!> PIPE_BUF,linux 2.6.11 以前,是4096,以后是65536。
11  #define TEN_MEG     36 * 10                        //!> ( 1024 * 1024 * 10)            
12  
13  int main()
14  {
15      int pipe_fd;
16      int res;
17      int open_mode =O_WRONLY;                     //!> 生产者:只是写data就可以了~
18     
19      int bytes =0;
20      char buffer[BUFFER_SIZE + 1] ="abcdefghijklmnopqrstuvwxyz";      //!> 36 个测试字符
21     
22     
23     
24     
25      if( access(FIFO_NAME, F_OK ) == -1)            //!> if 文件不存在( if 文件存在,那么access返回值是0 )
26      {
27         res =mkfifo( FIFO_NAME, 0777);            //!> 文件不存在就创建文件
28        
29         if( res != 0)                                 //!> 文件创建成功就返回0,否则返回-1,此处就是没有成功的情况
30         {
31            fprintf(stderr, "Can't create fifo %s\n", FIFO_NAME );
32            exit(EXIT_FAILURE );
33         }
34      }
35     
36     printf("Process %d opening  FIFO O_WRONLY \n", getpid());
37     
38      pipe_fd =open( FIFO_NAME, open_mode);                  //!> 打开创建的文件是只写模式 ( 注意open返回的是文件描述符 )
39                                                              //!>从此处开始:生产者开始写文件,所以需要启动Device,那么就由“消费者”来执行CPU
40      printf("Process %d ---> FILE  ID: %d\n",getpid(), pipe_fd );
41  
42      if( pipe_fd!= -1 )                        //!>对于open来说,成功返回FILE_ID,失败返回-1 ( 此处是成功~ )
43     {   
44         char test_char ='0';   
45           
46         while( bytes< TEN_MEG)                             //!> 指定大小为TEN_MEG
47         {
48           //!>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>      
49           test_char++;                  //!> 作为测试字符(标志每次读出来的是不是写入的还是仅仅是开头的数据 )
50            int len =strlen( buffer);                                //!> 测试字符串处理( 仅仅是测试而已 )
51            buffer[len]= test_char;                                 
52           buffer[len+1] = '\0';
53           //!>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
54           
55            res = write(pipe_fd, buffer, BUFFER_SIZE ); //!> 将数据写到文件中   (注意返回的是一次写入的字节数 )
56           
57            if( res ==-1 )
58            {
59               fprintf(stderr, "Write error on pipe\n" );
60               exit(EXIT_FAILURE );
61            }
62           
63           printf("生产者写入:--->  ");
64            puts( buffer);
65            bytes +=res;
66         }
67         close(pipe_fd );                                          //!> 关闭文件描述符( 也就是关闭文件s )
68      }
69      else
70      {
71         exit(EXIT_FAILURE );
72      }
73  
74      printf("Process %d   finish... \n",getpid() );
75  
76      exit( 0);
77  }
 1  #include <stdio.h>
 2  #include <stdlib.h>
 3  #include <string.h>
 4  #include <fcntl.h>
 5  #include <limits.h>
 6  #include <sys/types.h>
 7  #include <sys/stat.h>
 8  
 9  #define  FIFO_NAME   "/tmp/Linux/my_fifo" 
10  
11  //!> 注意消费者需要访问的路径就是“生产者”的写入路径文件(一个写,一个读)
12  
13  #define  BUFFER_SIZE 40                          
14  
15   //!>PIPE_BUF                  //!> PIPE_BUF,linux 2.6.11 以前,是4096,以后是65536。
16  
17  int main()
18  {
19      int pipe_fd;
20      int res;
21      int open_mode =O_RDONLY;                     //!> 消费者只读
22      int bytes =0;
23      char buffer[BUFFER_SIZE + 1];
24     
25      memset(buffer, '\0', sizeof( buffer ));            //!> 分配给buffer结束字符值而已
26     
27      printf("Process %d opening FIFO O_RDONLY \n", getpid() );
28     
29      pipe_fd =open( FIFO_NAME, open_mode);      //!> 打开已有的文件只读
30     
31      printf("Process %d result %d \n", getpid(), pipe_fd );
32     
33      if( pipe_fd!= -1 )
34      {
35         res = read(pipe_fd, buffer, BUFFER_SIZE);      //!> 读取第一次( 以防没有数据 )
36         while( res> 0 )
37         {
38            bytes +=res;
39           
40           printf("消费者读出:--->  ");
41            puts( buffer);
42           
43            res = read(pipe_fd, buffer, BUFFER_SIZE);   //!>从文件中读取data到buffer中   
44         }
45        
46         close(pipe_fd );
47      }
48      else
49      {
50         exit(EXIT_FAILURE );
51      }
52     
53     printf("Process %d finished, %d bytes read/n", getpid(),bytes); 
54     exit(EXIT_SUCCESS);   
55  }

3.运行及结果分析:

原理:消费者和生产者共用这个 有名pipe(FIFO),本质相当与是指针而已,

都往后只,取值也往后取值,所以每次取的顺序就是写入的顺序

编译这两个程序:

gcc –o c cons.c

gcc –o p per.c

运行这两个程序:

将生产者程序后台运行

./p&

再运行消费者程序

./c

终端COPY:

pt@ubuntu:~/桌面/net programming/进程通信/FIFO/生产者消费者$ ./p&

[1] 6055

Process 6055 opening FIFO O_WRONLY

pt@ubuntu:~/桌面/net programming/进程通信/FIFO/生产者消费者$ ./c

Process 6056 opening FIFO O_RDONLY

Process 6056 result 3

Process 6055 ---> FILE ID: 3

生产者写入:---> abcdefghijklmnopqrstuvwxyz1 //!> 说明:生产者的读出就是写入的内容

生产者写入:---> abcdefghijklmnopqrstuvwxyz12 //!> 也就是说:指针是跟着走的,并不是普通的文件

消费者读出:---> abcdefghijklmnopqrstuvwxyz1

生产者写入:---> abcdefghijklmnopqrstuvwxyz123

消费者读出:---> abcdefghijklmnopqrstuvwxyz12

生产者写入:---> abcdefghijklmnopqrstuvwxyz1234

消费者读出:---> abcdefghijklmnopqrstuvwxyz123

生产者写入:---> abcdefghijklmnopqrstuvwxyz12345

消费者读出:---> abcdefghijklmnopqrstuvwxyz1234

生产者写入:---> abcdefghijklmnopqrstuvwxyz123456

消费者读出:---> abcdefghijklmnopqrstuvwxyz12345

生产者写入:---> abcdefghijklmnopqrstuvwxyz1234567

消费者读出:---> abcdefghijklmnopqrstuvwxyz123456

生产者写入:---> abcdefghijklmnopqrstuvwxyz12345678

消费者读出:---> abcdefghijklmnopqrstuvwxyz1234567

生产者写入:---> abcdefghijklmnopqrstuvwxyz123456789

消费者读出:---> abcdefghijklmnopqrstuvwxyz12345678

消费者读出:---> abcdefghijklmnopqrstuvwxyz123456789

Process 6055 finish...

Process 6056 finished, 360 bytes read/n[1]+ Done ./p

四.

1.简介

server 要以一个熟知路径创建一个 FIFO 来监听所有的 client 的请求!所以可以是开启读pipe口,关闭写口

对于子进程来说,就是要写入数据就可以了!

但是为了返回server的反馈数据,那么子进程还是需要pipe来接受data fromserver;可以以自己的ID来创建!

2.代码

  1 #include <stdio.h>
  2  #include <stdlib.h>
  3  #include <string.h>
  4  #include <limits.h>
  5  #include <fcntl.h>
  6  #include <sys/types.h>
  7  #include <sys/stat.h>
  8  
  9  #define SERVER_FIFO_NAME   "/tmp/Linux/server_fifo"
 10  #define CLIENT_FIFO_NAME   "/tmp/Linux/client_%d_fifo"        
 11   //!>注意对于不同的client需要创建不同的自己的FIFO(可以根据自己唯一的pid来格式化)
 12  
 13  #define BUFFER_SIZE            PIPE_BUF
 14  #define MESSAGE_SIZE          20
 15  #define NAME_SIZE                256
 16  
 17  typedef struct message                                    //!> message数据结构
 18  {
 19      pid_t pid;
 20      char data[MESSAGE_SIZE + 1];
 21  }message;
 22  
 23  
 24  
 25  #include "cs.h"
 26  
 27  int main()
 28  {
 29      int server_fifo_fd;         //!> 打开server FIFO的描述符
 30      int client_fifo_fd;         //!> 打开client FIFO的描述符
 31  
 32      message msg;         //!> 接收client的请求 de 信息
 33     
 34      char  *p;               //!> 此value仅仅是为了简单处理data而已
 35     
 36      char client_fifo_name[NAME_SIZE];                     //!>先获得client的msg,取出client的pid,拼接成client的pid,用于反馈信息
 37     
 38      if( (access( SERVER_FIFO_NAME, F_OK ) ) == -1)      //!> if server的FIFO还不存在,就创建FIFO文件
 39      {
 40         if( (mkfifo( SERVER_FIFO_NAME, 0777 ) ) == -1)      //!> 创建server的FIFO
 41         {
 42           printf("Fail  To Create SERVER  FIFO ");
 43            exit(EXIT_FAILURE);                              //!> failure
 44         }
 45      }
 46     
 47     server_fifo_fd = open( SERVER_FIFO_NAME, O_RDONLY );
 48     
 49      if(server_fifo_fd == -1)                                    //!> fail to open the fifo file
 50      {
 51         printf("Failto open server_fifo_file");
 52         exit(EXIT_FAILURE );
 53     }      
 54     
 55     sleep(5);                                               
 56     
 57      while( (read( server_fifo_fd, &msg, sizeof( msg ) ) )> 0)     
 58     //!> exist themsg( 主要是为了获取data加以处理,还有:获取client的pid,来获得反馈的client的FIFO PIPE )
 59     {                                                      
 60     //!>注意:此处一定是while不是if,因为有多个客户端,所以需要一个所谓死循环(也就是当最后一个客户都关闭就结束)
 61         p =msg.data;            //!> 指针处理(简单处理数据而已)
 62         while( *p)                //!> 当字符串还没有结束
 63         {
 64            ( *p ) =toupper( *p);   //!> 处理成大写字母而已
 65            p++;
 66         }
 67        
 68         sprintf(client_fifo_name, CLIENT_FIFO_NAME, msg.pid);         //!> 将数据格式化成client的标准名称
 69        
 70        client_fifo_fd = open( client_fifo_name, O_WRONLY );
 71         if(client_fifo_fd == -1)      //!> Fait to open
 72         {
 73            printf("Fait to open client FIFO..." );
 74            exit(EXIT_FAILURE );
 75        }   
 76        
 77         write(client_fifo_fd, &msg, sizeof( msg ));                     //!> write into client fifo
 78         close(client_fifo_fd);      
 79      }
 80     close(server_fifo_fd); 
 81     unlink(SERVER_FIFO_NAME);                                    //!> 关闭链接
 82  
 83     exit(EXIT_SUCCESS);
 84  }
 85  
 86  
 87  
 88  #include "cs.h"
 89  
 90  int main()
 91  {
 92      int server_fifo_fd;
 93      int client_fifo_fd;
 94     
 95      char client_fifo_name[NAME_SIZE];
 96     
 97      message msg;
 98      msg.pid =getpid();
 99      sprintf(client_fifo_name, CLIENT_FIFO_NAME, getpid());      //!> 格式化此client的名称
100  
101      if( (access( client_fifo_name, F_OK ) ) == -1)               //!>没有此FIFO文件就创建   
102      {
103         if( (mkfifo( client_fifo_name, 0777 ) ) == -1)               //!> Fail to create client fifo
104         {
105               printf("Fail to create client fifo..." );
106               exit(EXIT_FAILURE );
107         }
108      }
109     
110      server_fifo_fd = open( SERVER_FIFO_NAME, O_WRONLY);   //!> 写入内容
111      if( server_fifo_fd == -1 )
112      {
113          printf("Failto open server fifo...");
114          exit(EXIT_FAILURE );
115      }         
116      
117      sprintf( msg.data, "hello from %d...", msg.pid );                     //!> 格式化到msg中等待发送
118      
119      printf( "%d  send the msg...", getpid() );
120      write( server_fifo_fd, &msg, sizeof( msg ) );
121      close( server_fifo_fd);   
122        
123     client_fifo_fd = open( client_fifo_name, O_RDONLY );
124      if(client_fifo_fd == -1 )
125      {
126         printf("Failto open client fifo...");
127         exit(EXIT_FAILURE );
128     }      
129  
130      if( ( read(client_fifo_fd, &msg, sizeof( msg ) ) )> 0 )
131      {
132         printf("\nClient %d recived msg: ---> %s \n", msg.pid,msg.data );
133      }
134           
135     close(client_fifo_fd); 
136     unlink(client_fifo_name);       
137     
138      exit(EXIT_SUCCESS );
139  }

最后来说:其实本质就是 创建一个文件作为交换区而已!结果也就是创建文件,打开文件,操作文件。。。