`

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一样可以以全双工的形式来使用,原理也是一个进程同时打开读和写的文

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


分享到:
评论

相关推荐

    fifo源代码

    它允许进程间通信(IPC),使得数据可以从一个进程写入,另一个进程读出,遵循FIFO规则。 2. **同步和信号量**:在多线程或多进程环境中,为了确保正确访问FIFO,可能需要使用同步机制,如互斥锁(mutex)或信号量...

    FIFO配合管道PIPE,实现FIFO传递数据,PIPE触发epoll,异步IO效果

    在IT行业中,FIFO(First In First Out)和管道(PIPE)是进程间通信(IPC,Inter-Process Communication)的两种重要方式。FIFO是一种特殊的文件类型,它遵循先进先出的原则,允许不同进程通过文件系统进行数据交换...

    Linux进程通信--FIFO(写)

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

    fifo.rar_fifo_fifo lin_fifo linux_linux fifo_进程间通信

    其中,FIFO(First In First Out)也称为命名管道,是一种简单但有效的 IPC 形式。FIFO 提供了一种半双工通信方式,即数据只能在一个方向上流动,但可以在两个进程中传递。 标题中的"fifo.rar_fifo_fifo lin_fifo ...

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

    在Linux操作系统中,进程间通信(IPC,Inter-Process Communication)是多个进程之间共享数据、交换信息的关键技术。本文将详细讲解如何通过FIFO(First In First Out,先进先出)这种特殊的管道通信机制实现进程间...

    fifo.zip_fifo_linux fifo

    在Linux操作系统中,FIFO(First In First Out)是一种特殊的文件类型,也称为命名管道,它提供了一种进程间通信(IPC,Inter-Process Communication)的方式。本压缩包中的源码`wfifo.c`和`rfifo.c`分别展示了如何...

    管道通信fifo程序

    管道通信,也称为命名管道(Named Pipe)或FIFO(First In First Out),是Linux和Unix-like操作系统中的一种进程间通信(IPC, Inter-Process Communication)机制。它允许不同进程之间进行单向或双向的数据传输,...

    FIFO.zip_fifo

    FIFO是一种特殊的数据结构,广泛应用于操作系统中,特别是在进程间通信(IPC,Inter-Process Communication)时,如管道(pipe)。 描述中提到的"FIFO test code"是用于测试FIFO读写功能的应用程序。这个应用程序...

    fifo.rar_fifo_同步fifo

    在操作系统中,FIFO常用于实现进程间通信(IPC)的管道,以及在硬件层面,如内存缓存和I/O设备的数据缓冲。 **同步FIFO** 在多线程或多进程环境中,当两个或更多组件同时访问FIFO时,可能会引发数据竞争和不一致性...

    FIFO的程序及定义

    3. **管道通信**:在进程间通信(IPC)中,FIFO(也被称为命名管道)是一种同步通信机制。两个进程可以通过FIFO进行数据交换,数据的读取和写入遵循FIFO规则,即先写入的数据先被读出。 4. **硬件设备**:在硬件...

    6_pipe_fifo

    本文将详细探讨两种常见的IPC机制:pipe(管道)和fifo(无名管道),并结合提供的源码文件"6_pipe"和"6_fifo"进行深入解析。 1. **管道(Pipe)** - **概念**:管道是一种半双工的通信方式,允许数据在一个方向上...

    fifo.rar_Visual C++ fifo_系统调用FIFO_队列fifo

    在操作系统中,FIFO通常用于进程间的通信(IPC,Inter-Process Communication)。例如,通过创建命名管道(named pipe),两个或多个进程可以共享一个FIFO数据流进行数据传输。在Windows系统中,这可以通过创建FILE_...

    FIFO.rar_fifo

    在操作系统中,FIFO也被用作进程间通信(IPC)的一种方式,称为命名管道。在这种情况下,多个进程可以读写同一个FIFO,遵循先进先出的原则。 7. **性能优化**: 对于高性能系统,FIFO可能会设计成流水线式,以...

    进程间的通讯demo——fifo

    FIFO,也被称为命名管道,是一种简单的IPC形式,其工作原理类似于物理世界的管道,数据按照进入的顺序被取出。在Unix和类Unix系统如Linux中,FIFO是一种特殊的文件类型,可以在不同的进程之间提供单向或双向的数据...

    FIFO例程,标题要求是个字,汗

    Unix/Linux系统中,FIFO也被称为命名管道,是进程间通信(IPC)的一种机制。两个不相关的进程可以通过同一个FIFO进行数据交换,一个进程写入,另一个进程读取。创建FIFO使用`mkfifo`命令,然后进程通过文件描述符...

    命名管道(FIFO)示例代码

    命名管道(FIFO)在Linux系统编程中是一种重要的进程间通信(IPC,Inter-Process Communication)机制。它允许两个没有亲缘关系的进程之间进行数据交换,类似于物理世界的管道,数据从一端流入,另一端流出。FIFO是...

    使用fifo实现tftp的简单功能

    - **Unix/Linux系统编程**:包括文件操作、进程间通信(IPC)以及错误处理。 - **FIFO的工作原理**:理解如何使用`mkfifo()`创建管道,以及如何通过`open()`, `read()`, `write()`等函数进行数据交换。 - **TFTP协议...

    fifo.rar_fifo arm

    在进程间通信(IPC,Inter-Process Communication)中,一个进程将数据写入FIFO,另一个进程则读取这些数据。如果读写速度不匹配,FIFO的大小决定了可以存储多少未处理的数据。 2. **Linux中的FIFO**:在Linux系统...

    liux下C编程关于fifo使用的例子.rar_c fi_fifo_fifo linux_fifo和lur例子

    在Linux操作系统中,FIFO(First In First Out)是一种特殊的文件类型,也称为命名管道,它提供了进程间通信(IPC, Inter-Process Communication)的一种方式。C编程中的FIFO操作可以实现不同进程间的同步和数据交换...

    fifo.zip_fifo

    在嵌入式Linux系统开发中,FIFO(First In First Out,先进先出)是一种重要的进程间通信(IPC,Inter-Process Communication)机制。标题"fifo.zip_fifo"和描述中的关键词"FIFO"提示我们,这个压缩包包含的是与FIFO...

Global site tag (gtag.js) - Google Analytics