`

IPC FIFO

 
阅读更多

FIFO

1、函数列表

<!--[if !supportLists]-->Ø <!--[endif]-->int mkfifo(const char *pathname, mode_t mode);

如果pathname指向的FIFO不存在,则创建FIFO,此时返回0;如果pathname指向的FIFO已经存在,则返回-1errno==EEXIST

关于mode,此函数已隐含包含O_CREATEO_EXCL,也就是说要么创建一个新的FIFO,要么返回EEXIST错误。指定S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH表示FIFO允许用户读、用户写、组成员读和其他用户读。

<!--[if !supportLists]-->Ø <!--[endif]-->int open(const char *pathname, int flags, mode_t mode);

一个FIFO创建完后(或者是已经存在),它必须或者打开用于读,或者打开用于写。对于一个进程而言,FIFO不能打开来既读又写,因为FIFO是半双工的。

<!--[if !supportLists]-->Ø <!--[endif]-->ssize_t write(int fd, const void *buf, size_t count);

<!--[if !supportLists]-->Ø <!--[endif]-->ssize_t read(int fd, void *buf, size_t count);

<!--[if !supportLists]-->Ø <!--[endif]-->int close(int fd); //#include <unistd.h>

操作文件(广义的:包括普通文件、系统设备和管道)的读写关闭函数。其中fd为文件描述字。

<!--[if !supportLists]-->Ø <!--[endif]-->int unlink(const char *pathname);

此函数将FIFO从系统中彻底删除。成功返回0,失败返回-1

2、实例解析

<!--[if !supportLists]-->Ø <!--[endif]-->Simplefifo

FIFO的基本使用,在父子进程中使用单个FIFO,父进程向FIFO的写文件描述字写进数据,子进程从FIFO的读文件描述字中读出数据。

<!--[if gte vml 1]><v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"> <v:stroke joinstyle="miter" /> <v:formulas> <v:f eqn="if lineDrawn pixelLineWidth 0" /> <v:f eqn="sum @0 1 0" /> <v:f eqn="sum 0 0 @1" /> <v:f eqn="prod @2 1 2" /> <v:f eqn="prod @3 21600 pixelWidth" /> <v:f eqn="prod @3 21600 pixelHeight" /> <v:f eqn="sum @0 0 1" /> <v:f eqn="prod @6 1 2" /> <v:f eqn="prod @7 21600 pixelWidth" /> <v:f eqn="sum @8 21600 0" /> <v:f eqn="prod @7 21600 pixelHeight" /> <v:f eqn="sum @10 21600 0" /> </v:formulas> <v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect" /> <o:lock v:ext="edit" aspectratio="t" /> </v:shapetype><v:shape id="_x0000_i1025" type="#_x0000_t75" style='width:368.25pt; height:202.5pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image001.png" o:title="" /> </v:shape><![endif]--><!--[if !vml]--><!--[endif]-->

//simplefifo.c

#include <sys/types.h>

#include <sys/stat.h>

#include <pthread.h>

#include <unistd.h>

#include <stdio.h>

#include <fcntl.h> //O_RDONLY

#include <errno.h>

#define MAX_LENGTH 10

int main(int argc, char **argv)

{

int readfd, writefd;

pid_t childpid;

int w_length;

int r_length;

char buffer[MAX_LENGTH];

if ((mkfifo("/tmp/fifo.1", (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))<0) && (errno == EEXIST))

printf("can't create %s", "/tmp/fifo.1");

if((childpid=fork())==0) //child process server

{

readfd = open("/tmp/fifo.1", O_RDONLY, 0);

r_length=read(readfd,buffer,MAX_LENGTH);

printf("r_length===%d/n",r_length);

printf("buffer===%s/n",buffer);

printf("buffer===%d/n",strlen(buffer));

close(readfd);

}

else

{

writefd=open("/tmp/fifo.1", O_WRONLY, 0);

w_length=write(writefd,"abcdef",11);

printf("w_length===%d/n",w_length);

waitpid(childpid, NULL, 0);

close(writefd);

unlink("/tmp/fifo.1");

}

}

# gcc simplefifo.c -lpthread -o simplefifo

<!--[if !supportLists]-->Ø <!--[endif]-->norelationsprocessfifo

没有亲缘关系的进程之间使用一个FIFO。将其中阻塞的进程称为服务端进程,将另一个称为客户端进程。客户端向FIFO写数据,服务端从FIFO读取数据。

<!--[if gte vml 1]><v:shape id="_x0000_i1026" type="#_x0000_t75" style='width:369pt;height:199.5pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image003.png" o:title="" /> </v:shape><![endif]--><!--[if !vml]--><!--[endif]-->

// norelationsprocessfifo_server.c

#include <sys/types.h>

#include <sys/stat.h> //mkfifo

#include <errno.h> // errno

#include <fcntl.h> //O_RDONLY

int main(int argc, char **argv)

{

int readfd;

int r_length;

char buffer[10];

if ((mkfifo("/tmp/fifo.1", (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))<0) && (errno == EEXIST))

printf("can't create %s", "/tmp/fifo.1");

printf("befor open fifo/n");

readfd = open("/tmp/fifo.1", O_RDONLY, 0);

printf("have open and befor read/n");

r_length=read(readfd,buffer,10);

printf("have read and r_length=%d;strlen(buffer)=%d;buffer=%s;/n",r_length,strlen(buffer),buffer);

close(readfd);

}

//#gcc norelationsprocessfifo_server.c –o norelationsprocessfifo_server

// norelationsprocessfifo_client.c

#include <sys/types.h>

#include <sys/stat.h> //mkfifo

#include <fcntl.h> //O_RDONLY

int main(int argc, char **argv)

{

int writefd;

int w_length;

printf("befor open fifo/n");

sleep(5);

writefd=open("/tmp/fifo.1", O_WRONLY, 0);

printf("fifo have open and befor write/n");

sleep(5);

w_length=write(writefd,"abcdef",11);

printf("have write/n");

sleep(5);

close(writefd);

unlink("/tmp/fifo.1");

}

//#gcc norelationsprocessfifo_client.c –o norelationsprocessfifo_client

服务端创建FIFO,并阻塞(等待客户端打开FIFO写文件描述字)打开FIFO读文件描述字,然后阻塞(等待客户端向FIFO的写文件描述字写进数据)从FIFO读文件描述字中读取数据,最后关闭读文件描述字。

客户端打开FIFO的写文件描述字,然后向FIFO写文件描述字中写进数据,然后关闭写文件描述字,最后删除FIFO

通过程序的输出可以很明显的看出阻塞过程,其中方框中输出对应的服务端openread函数即为阻塞点,示意图如下:

<!--[if gte vml 1]><v:shape id="_x0000_i1027" type="#_x0000_t75" style='width:411.75pt;height:278.25pt'> <v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image005.png" o:title="" /> </v:shape><![endif]--><!--[if !vml]--><!--[endif]-->

阻塞输出示意图

阻塞发生在服务端,因此只需要在服务端以非阻塞方式(O_NONBLOCK)打开FIFO的读文件描述字,则open函数和read函数均以非阻塞方式执行。

//norelationsprocessfifo_noblock_server.c

#include <sys/types.h>

#include <sys/stat.h> //mkfifo

#include <errno.h> // errno

#include <fcntl.h> //O_RDONLY

int main(int argc, char **argv)

{

int readfd;

int r_length;

char buffer[10];

if ((mkfifo("/tmp/fifo.1", (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))<0) && (errno != EEXIST))

printf("can't create %s", "/tmp/fifo.1");

printf("befor open fifo/n");

readfd = open("/tmp/fifo.1", O_RDONLY|O_NONBLOCK, 0);

printf("have open and befor read/n");

int p=0;

while(1)

{

r_length=read(readfd,buffer,10);

printf("%d/n",p++);

if(r_length>0)

{

printf("have read and r_length=%d;strlen(buffer)=%d;buffer=%s;/n",r_length,strlen(buffer),buffer);

sleep(3);

}

}

close(readfd);

}

//#gcc norelationsprocessfifo_noblock_server.c –o noblockserver

由于read函数也不发生阻塞,因此必须有一个无限循环等待客户端发送数据。

norelationsprocessfifo_noblock_client.c代码和norelationsprocessfifo_client.c相同。

<!--[if !supportLists]-->Ø <!--[endif]-->structmesg

进程之间可以通过FIFO传递struct变量数据。

//structmesg.h

#include <sys/types.h>

#include <sys/stat.h> //mkfifo

#include <fcntl.h> //O_RDONLY

#include <limits.h> /* PIPE_BUF */

#define MAXMESGDATA (PIPE_BUF - 2*sizeof(long))

#define MESGHDRSIZE (sizeof(struct mymesg) - MAXMESGDATA)

struct mymesg {

long mesg_len; /* #bytes in mesg_data, can be 0 */

long mesg_type; /* message type, must be > 0 */

char mesg_data[MAXMESGDATA];

};

//structmesg_server.c

#include <errno.h>

#include "structmesg.h"

int main(int argc, char **argv)

{

int readfd;

size_t len;

ssize_t n;

struct mymesg mesg;

if ((mkfifo("/tmp/fifo.1", (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))<0) && (errno == EEXIST))

printf("can't create %s", "/tmp/fifo.1");

readfd = open("/tmp/fifo.1", O_RDONLY, 0);

if ( (n = read(readfd, &mesg, MESGHDRSIZE)) == 0)

//第一次读取固定长度数据,得到数据类型和结构体数据长度

{

printf("end of file!/n"); //到达文件的末尾,没有数据

return(0); /* end of file */

}

else if (n != MESGHDRSIZE)

{

printf("message header: expected %d, got %d", MESGHDRSIZE, n); //数据有误,长度不一致

return(0);

}

if ( (len = mesg.mesg_len) > 0)//结构体中有具体的数据,长度不为0

if ( (n = read(readfd, mesg.mesg_data, len)) != len)

//第二次读取具体的结构体数据

{

printf("message data: expected %d, got %d", len, n);//数据有误,长度不一致

return(0);

}

printf("mesg_len=%d/tmesg_type=%d/tmesg_data=%s/n",mesg.mesg_len,mesg.mesg_type,mesg.mesg_data);

close(readfd);

return 0;

}

注意判断各种可能的情况。第一次读取结构体数据长度和类型是用struct mymesg指针作为入参,那么只填充了前面两个成员变量,这可以从struct的存储结构来理解;第二次读取是以struct mymesg的成员mesg_data作为入参。

#include "structmesg.h"

int main(int argc, char **argv)

{

int writefd;

struct mymesg mesg;

writefd = open("/tmp/fifo.1", O_WRONLY, 0);

mesg.mesg_len=10;

mesg.mesg_type=1;

strcpy(mesg.mesg_data,"abcdefghij");

write(writefd,&mesg,MESGHDRSIZE+mesg.mesg_len);

close(writefd);

unlink("/tmp/fifo.1");

}

3、小结

<!--[if !supportLists]-->Ø <!--[endif]-->pipe(管道)没有名称,因此只能在父子进程之间使用(不考虑传递文件描述字的情况);

FIFO(具名管道)有名称,因此可以在非亲缘关系进程之间使用。

<!--[if !supportLists]-->Ø <!--[endif]-->FIFO是一种只能在单台主机上使用的IPC(进程间通信)形式。尽管在文件系统中有名

字,它们也只能用在本地文件系统中,而不能用在通过NFS安装的文件系统中。

<!--[if !supportLists]-->Ø <!--[endif]-->创建pipe和获得管道的文件描述字只需要pipe(int fd[2])函数,而mkfifo创建FIFOopen

获得文件描述字。

关闭pipe的文件描述字以后,pipe就自动消失了,而对于FIFO,不仅要关闭其文件描述字,还要调用unlink函数来彻底删除。

<!--[if !supportLists]-->Ø <!--[endif]-->任意时刻打开管道和FIFO描述字的数目是有一定限制的;

管道和FIFOwrite操作的原子性的前提是数据量小于PIPE_BUF,在一次写操作过程中数据量小于PIPE_BUF时,写操作原子性能够保证;

数据是面向字节流的,也就是从管道/FIFO一端读出的100个字节,另一端可能1write100个字节,可能250个字节,可能520个字节。也就是无法区别对端一次性write的数据量。

针对管道/FIFO数据字节流的特点,在两端必须由应用自定义解释,也就是编制数据传输的协议。

<!--[if !supportLists]-->Ø <!--[endif]-->FIFOpipe一样可以以全双工的形式来使用,原理也是一个进程同时打开读和写的文

件描述字,但全双工使用较少,尽量采用半双工形式。


分享到:
评论

相关推荐

    Linux进程通信--FIFO(写)

    Linux进程间通信之FIFO,适用于任意进程间. 此C文件为FIFO的写端

    Linux下进程间通信FIFO演示程序

    一个简单程序,演示了Linux下的FIFO IPC机制 http://blog.csdn.net/ZhengZhiRen/archive/2010/05/21/5613843.aspx

    Linux进程通信--FIFO(读)

    Linux进程间通信之FIFO,适用于任意两个进程间.此C文件件为读端.

    IPC 读书笔记及测试程序

    IPC 读书笔记及测试程序 PIPE FIFO Mutex Conditional Variable Semophore

    6_pipe_fifo

    linux 进程间通信 pipe和fifo实现 。(此为博客http://blog.csdn.net/shallnet 文章对应源码下载)

    ipc-bench:进程间通信技术基准

    IPC工作台 Linux和OS X上各种进程间通信(IPC)方法的示例实现和基准。 光谱 实施以下IPC方法。...FIFO(命名管道) 265,823 msg / s 254,880 msg / s 共享内存 4,702,557消息/秒 1,659,291消息/秒 内存映射文

    UNIX网络编程,第2卷:进程间通信(第二版)

    本书从对Posix IPC和System V IPC的内部结构开始讨论,全面深入地介绍了4种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号量)、共享内存(匿名共享内存、具名共享内存...

    UNIX网络编程_卷2_进程间通信

    本书从对Posix IPC和System V IPC的内部结构开始讨论,全面深入地介绍了4种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号量)、共享内存(匿名共享内存、具名...

    UNIX环境高级编程_第二版中文

    本书从对Posix IPC和System V IPC的内部结构开始讨论,全面深入地介绍了4种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号量)、共享内存(匿名共享内存、具名...

    UNIX网络编程 第2卷 进程间通信

    本书从对Posix IPC和System V IPC的内部结构开始讨论,全面深入地介绍了4种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号量)、共享内存(匿名共享内存、具名...

    UNIX网络编程 第一卷+第二卷

    本书从对Posix IPC和System V IPC的内部结构开始讨论,全面深入地介绍了4种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号量)、共享内存(匿名共享内存、具名...

    UNIX网络编程-第2卷 程间通信 源代码

    本书从对Posix IPC和System V IPC的内部结构开始讨论,全面深入地介绍了4种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号量)、共享内存(匿名共享内存、具名...

    UNIX网络编程第一卷

    本书从对Posix IPC和System V IPC的内部结构开始讨论,全面深入地介绍了4种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号量)、共享内存(匿名共享内存、具名...

    UNIX网络编程 第2卷 进程间通信 pdf

    本书从对Posix IPC和System V IPC的内部结构的综合讨论开始,具体阐述并比较了四种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号灯)、共享内存区(匿名共享内存区;...

    UNIX网络编程.卷2:进程间通信(第2版)

    卷2:进程间通信(第2版)》从对Posix IPC和System V IPC的内部结构开始讨论,全面深入地介绍了4种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号量)、共享内存(匿名...

    Unix网络编程第2卷进程间通信

    本书从对Posix IPC和System V IPC的内部结构开始讨论,全面深入地介绍了4种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号量)、共享内存(匿名共享内存、具名...

    UNIX网络编程 第2版 第2卷 进程间通信.part1.rar

    本书从对PosixIPC和SystemVIPC的内部结构的综合讨论开始,具体阐述并比较了四种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号灯)、共享内存区(匿名共享内存区...

    UNIX网络编程 第2版 第2卷 进程间通信.part3.rar

    本书从对PosixIPC和SystemVIPC的内部结构的综合讨论开始,具体阐述并比较了四种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号灯)、共享内存区(匿名共享内存区...

Global site tag (gtag.js) - Google Analytics