您的位置:首页 > 运维架构 > Linux

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

2012-03-20 12:00 225 查看
一.

一些简单理解:

我们知道管道是没有标志的,所以只能是在同一个进程组中进行通信,不同的祖先产生的进程之间是不可以的!!所以此处引入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.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.代码:

#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 );

}

最后来说:其实本质就是 创建一个文件作为交换区而已!结果也就是创建文件,打开文件,操作文件。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: