Linux进程通信(System V)第二节------>FIFO

来源:岁月联盟 编辑:exp 时间:2012-03-20
一. 一些简单理解:我们知道管道是没有标志的,所以只能是在同一个进程组中进行通信,不同的祖先产生的进程之间是不可以的!!所以此处引入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选项添加的,它也表示是这是一个管道。  二. #include<stdio.h>  #include<stdlib.h> #include<sys/types.h> #include<sys/stat.h>     int main() {       intres;        if ( ( res =mkfifo("/tmp/my_fifo", 0777) ) == 0 )       //!> 对于mkfifo来说:成功则返回0,否则返回-1     {                                                 //!>注意全名就是   /tmp/my_fifo 其实就是tmp路径下的 my_fifo 文件        printf("FIFOcreated/n");      }       return0;    //!> exit(EXIT_SUCCESS);} 三. 1.简介:两个独立的程序:1.     生产者程序,它在需要时创建管道,然后尽可能快地向管道中写入数据。2.     消费者程序,它从FIFO中读取数据并丢弃它们。 2.代码: #include <stdio.h>#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <limits.h>#include <sys/types.h>#include <sys/stat.h> #define FIFO_NAME   "/tmp/Linux/my_fifo"            //!> FIFO全名#define  BUFFER_SIZE 40                              //!> PIPE_BUF,linux 2.6.11 以前,是4096,以后是65536。#define TEN_MEG     36 * 10                        //!> ( 1024 * 1024 * 10)             int main(){    intpipe_fd;    intres;    intopen_mode =O_WRONLY;                     //!> 生产者:只是写data就可以了~       int bytes =0;    charbuffer[BUFFER_SIZE + 1] ="abcdefghijklmnopqrstuvwxyz";      //!> 36 个测试字符                if( access(FIFO_NAME, F_OK ) == -1)            //!> if 文件不存在( if 文件存在,那么access返回值是0 )    {       res =mkfifo( FIFO_NAME, 0777);            //!> 文件不存在就创建文件             if( res != 0)                                 //!> 文件创建成功就返回0,否则返回-1,此处就是没有成功的情况       {          fprintf(stderr, "Can't create fifo %s/n", FIFO_NAME );          exit(EXIT_FAILURE );       }    }      printf("Process %d opening  FIFO O_WRONLY /n", getpid());       pipe_fd =open( FIFO_NAME, open_mode);                  //!> 打开创建的文件是只写模式 ( 注意open返回的是文件描述符 )                                                            //!>从此处开始:生产者开始写文件,所以需要启动Device,那么就由“消费者”来执行CPU    printf("Process %d ---> FILE  ID: %d/n",getpid(), pipe_fd );     if( pipe_fd!= -1 )                        //!>对于open来说,成功返回FILE_ID,失败返回-1 ( 此处是成功~ )   {          chartest_char ='0';                   while( bytes< TEN_MEG)                             //!> 指定大小为TEN_MEG       {         //!>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>               test_char++;                  //!> 作为测试字符(标志每次读出来的是不是写入的还是仅仅是开头的数据 )          int len =strlen( buffer);                                //!> 测试字符串处理( 仅仅是测试而已 )          buffer[len]= test_char;                                          buffer[len+1] = '/0';         //!>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>                   res = write(pipe_fd, buffer, BUFFER_SIZE ); //!> 将数据写到文件中   (注意返回的是一次写入的字节数 )                   if( res ==-1 )          {             fprintf(stderr, "Write error on pipe/n" );             exit(EXIT_FAILURE );          }                  printf("生产者写入:--->  ");          puts( buffer);          bytes +=res;       }       close(pipe_fd );                                          //!> 关闭文件描述符( 也就是关闭文件s )    }    else    {       exit(EXIT_FAILURE );    }     printf("Process %d   finish... /n",getpid() );     exit( 0);}   #include <stdio.h>#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <limits.h>#include <sys/types.h>#include <sys/stat.h> #define  FIFO_NAME   "/tmp/Linux/my_fifo"  //!> 注意消费者需要访问的路径就是“生产者”的写入路径文件(一个写,一个读) #define  BUFFER_SIZE 40                            //!>PIPE_BUF                  //!> PIPE_BUF,linux 2.6.11 以前,是4096,以后是65536。 int main(){    intpipe_fd;    intres;    intopen_mode =O_RDONLY;                     //!> 消费者只读    int bytes =0;    charbuffer[BUFFER_SIZE + 1];       memset(buffer, '/0', sizeof( buffer ));            //!> 分配给buffer结束字符值而已       printf("Process %d opening FIFO O_RDONLY /n", getpid() );       pipe_fd =open( FIFO_NAME, open_mode);      //!> 打开已有的文件只读       printf("Process %d result %d /n", getpid(), pipe_fd );       if( pipe_fd!= -1 )    {       res = read(pipe_fd, buffer, BUFFER_SIZE);      //!> 读取第一次( 以防没有数据 )       while( res> 0 )       {          bytes +=res;                  printf("消费者读出:--->  ");          puts( buffer);                   res = read(pipe_fd, buffer, BUFFER_SIZE);   //!>从文件中读取data到buffer中          }             close(pipe_fd );    }    else    {       exit(EXIT_FAILURE );    }      printf("Process %d finished, %d bytes read/n", getpid(),bytes);    exit(EXIT_SUCCESS);   } 3.运行及结果分析: 原理:消费者和生产者共用这个 有名pipe(FIFO),本质相当与是指针而已,      都往后只,取值也往后取值,所以每次取的顺序就是写入的顺序 编译这两个程序:gcc –o c cons.cgcc –o p per.c 运行这两个程序:               将生产者程序后台运行                ./p&               再运行消费者程序                ./c                       终端COPY:               pt@ubuntu:~/桌面/net programming/进程通信/FIFO/生产者消费者$ ./p& [1] 6055Process 6055 opening  FIFO O_WRONLY pt@ubuntu:~/桌面/net programming/进程通信/FIFO/生产者消费者$ ./c Process 6056 opening FIFO O_RDONLYProcess 6056 result 3Process 6055 ---> FILE  ID: 3生产者写入:--->  abcdefghijklmnopqrstuvwxyz1                           //!> 说明:生产者的读出就是写入的内容生产者写入:--->  abcdefghijklmnopqrstuvwxyz12                        //!> 也就是说:指针是跟着走的,并不是普通的文件消费者读出:---> abcdefghijklmnopqrstuvwxyz1生产者写入:--->  abcdefghijklmnopqrstuvwxyz123消费者读出:---> abcdefghijklmnopqrstuvwxyz12生产者写入:--->  abcdefghijklmnopqrstuvwxyz1234消费者读出:---> abcdefghijklmnopqrstuvwxyz123生产者写入:--->  abcdefghijklmnopqrstuvwxyz12345消费者读出:---> abcdefghijklmnopqrstuvwxyz1234生产者写入:--->  abcdefghijklmnopqrstuvwxyz123456消费者读出:---> abcdefghijklmnopqrstuvwxyz12345生产者写入:--->  abcdefghijklmnopqrstuvwxyz1234567消费者读出:---> abcdefghijklmnopqrstuvwxyz123456生产者写入:--->  abcdefghijklmnopqrstuvwxyz12345678消费者读出:---> abcdefghijklmnopqrstuvwxyz1234567生产者写入:--->  abcdefghijklmnopqrstuvwxyz123456789消费者读出:---> abcdefghijklmnopqrstuvwxyz12345678消费者读出:---> abcdefghijklmnopqrstuvwxyz123456789Process 6055   finish...Process 6056 finished, 360 bytes read/n[1]+ Done                   ./p  四. 1.简介server 要以一个熟知路径创建一个 FIFO 来监听所有的 client 的请求!所以可以是开启读pipe口,关闭写口对于子进程来说,就是要写入数据就可以了!但是为了返回server的反馈数据,那么子进程还是需要pipe来接受data fromserver;可以以自己的ID来创建! 2.代码:  #include <stdio.h>#include <stdlib.h>#include <string.h>#include <limits.h>#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h> #define SERVER_FIFO_NAME   "/tmp/Linux/server_fifo"#define CLIENT_FIFO_NAME   "/tmp/Linux/client_%d_fifo"         //!>注意对于不同的client需要创建不同的自己的FIFO(可以根据自己唯一的pid来格式化) #define BUFFER_SIZE            PIPE_BUF#define MESSAGE_SIZE          20#define NAME_SIZE                256 typedef structmessage                                    //!> message数据结构{    pid_tpid;    chardata[MESSAGE_SIZE + 1];}message;   #include "cs.h" int main(){    intserver_fifo_fd;         //!> 打开server FIFO的描述符    intclient_fifo_fd;         //!> 打开client FIFO的描述符     messagemsg;         //!> 接收client的请求 de 信息       char *p;               //!> 此value仅仅是为了简单处理data而已       charclient_fifo_name[NAME_SIZE];                     //!>先获得client的msg,取出client的pid,拼接成client的pid,用于反馈信息       if( (access( SERVER_FIFO_NAME, F_OK ) ) == -1)      //!> if server的FIFO还不存在,就创建FIFO文件    {       if( (mkfifo( SERVER_FIFO_NAME, 0777 ) ) == -1)      //!> 创建server的FIFO       {         printf("Fail  To Create SERVER  FIFO ");          exit(EXIT_FAILURE);                              //!> failure       }    }      server_fifo_fd = open( SERVER_FIFO_NAME, O_RDONLY );       if(server_fifo_fd == -1)                                    //!> fail to open the fifo file    {       printf("Failto open server_fifo_file");       exit(EXIT_FAILURE );   }            sleep(5);                                                      while( (read( server_fifo_fd, &msg, sizeof( msg ) ) )> 0)        //!> exist themsg( 主要是为了获取data加以处理,还有:获取client的pid,来获得反馈的client的FIFO PIPE )   {                                                         //!>注意:此处一定是while不是if,因为有多个客户端,所以需要一个所谓死循环(也就是当最后一个客户都关闭就结束)       p =msg.data;            //!> 指针处理(简单处理数据而已)       while( *p)                //!> 当字符串还没有结束       {          ( *p ) =toupper( *p);   //!> 处理成大写字母而已          p++;       }             sprintf(client_fifo_name, CLIENT_FIFO_NAME, msg.pid);         //!> 将数据格式化成client的标准名称            client_fifo_fd = open( client_fifo_name, O_WRONLY );       if(client_fifo_fd == -1)      //!> Fait to open       {          printf("Fait to open client FIFO..." );          exit(EXIT_FAILURE );      }                write(client_fifo_fd, &msg, sizeof( msg ));                     //!> write into client fifo       close(client_fifo_fd);          }   close(server_fifo_fd);    unlink(SERVER_FIFO_NAME);                                    //!> 关闭链接    exit(EXIT_SUCCESS);}   #include "cs.h" int main(){    intserver_fifo_fd;    intclient_fifo_fd;       charclient_fifo_name[NAME_SIZE];       messagemsg;    msg.pid =getpid();    sprintf(client_fifo_name, CLIENT_FIFO_NAME, getpid());      //!> 格式化此client的名称     if( (access( client_fifo_name, F_OK ) ) == -1)               //!>没有此FIFO文件就创建       {       if( (mkfifo( client_fifo_name, 0777 ) ) == -1)               //!> Fail to create client fifo       {             printf("Fail to create client fifo..." );             exit(EXIT_FAILURE );       }    }       server_fifo_fd = open( SERVER_FIFO_NAME, O_WRONLY);   //!> 写入内容    if( server_fifo_fd == -1 )    {        printf("Failto open server fifo...");        exit(EXIT_FAILURE );    }                 sprintf( msg.data, "hello from %d...", msg.pid );                     //!> 格式化到msg中等待发送        printf( "%d  send the msg...", getpid() );    write( server_fifo_fd, &msg, sizeof( msg ) );    close( server_fifo_fd);            client_fifo_fd = open( client_fifo_name, O_RDONLY );    if(client_fifo_fd == -1 )    {       printf("Failto open client fifo...");       exit(EXIT_FAILURE );   }           if( ( read(client_fifo_fd, &msg, sizeof( msg ) ) )> 0 )    {       printf("/nClient %d recived msg: ---> %s /n", msg.pid,msg.data );    }            close(client_fifo_fd);    unlink(client_fifo_name);              exit(EXIT_SUCCESS );} 最后来说:其实本质就是创建一个文件作为交换区而已!结果也就是创建文件,打开文件,操作文件。。。    摘自 shanshanpt的专栏