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 }
最后来说:其实本质就是 创建一个文件作为交换区而已!结果也就是创建文件,打开文件,操作文件。。。