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选项添加的,它也表示是这是一个管道。


.

#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] ="abcdefghijklmnopqrstuvwx yz";            //!> 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.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
生产者写入:--->    abcdefghijklmnopqrstuvwx yz1                                                      //!> 说明:生产者的读出就是写入的内容
生产者写入:--->    abcdefghijklmnopqrstuvwx yz12                                                //!> 也就是说:指针是跟着走的,并不是普通的文件
消费者读出:--->  abcdefghijklmnopqrstuvwx yz1
生产者写入:--->    abcdefghijklmnopqrstuvwx yz123
消费者读出:--->  abcdefghijklmnopqrstuvwx yz12
生产者写入:--->    abcdefghijklmnopqrstuvwx yz1234
消费者读出:--->  abcdefghijklmnopqrstuvwx yz123
生产者写入:--->    abcdefghijklmnopqrstuvwx yz12345
消费者读出:--->  abcdefghijklmnopqrstuvwx yz1234
生产者写入:--->    abcdefghijklmnopqrstuvwx yz123456
消费者读出:--->  abcdefghijklmnopqrstuvwx yz12345
生产者写入:--->    abcdefghijklmnopqrstuvwx yz1234567
消费者读出:--->  abcdefghijklmnopqrstuvwx yz123456
生产者写入:--->    abcdefghijklmnopqrstuvwx yz12345678
消费者读出:--->  abcdefghijklmnopqrstuvwx yz1234567
生产者写入:--->    abcdefghijklmnopqrstuvwx yz123456789
消费者读出:--->  abcdefghijklmnopqrstuvwx yz12345678
消费者读出:--->  abcdefghijklmnopqrstuvwx yz123456789
Process 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 );
}

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

你可能感兴趣的:(linux,server,File,System,buffer,Access)