FIFO
1、函数列表
<!--[if !supportLists]-->Ø
<!--[endif]-->int mkfifo(const char *pathname, mode_t
mode);
如果pathname指向的FIFO不存在,则创建FIFO,此时返回0;如果pathname指向的FIFO已经存在,则返回-1,errno==EEXIST。
关于mode,此函数已隐含包含O_CREATE和O_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。
通过程序的输出可以很明显的看出阻塞过程,其中方框中输出对应的服务端open和read函数即为阻塞点,示意图如下:
<!--[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创建FIFO,open
获得文件描述字。
关闭pipe的文件描述字以后,pipe就自动消失了,而对于FIFO,不仅要关闭其文件描述字,还要调用unlink函数来彻底删除。
<!--[if !supportLists]-->Ø
<!--[endif]-->任意时刻打开管道和FIFO描述字的数目是有一定限制的;
管道和FIFO的write操作的原子性的前提是数据量小于PIPE_BUF,在一次写操作过程中数据量小于PIPE_BUF时,写操作原子性能够保证;
数据是面向字节流的,也就是从管道/FIFO一端读出的100个字节,另一端可能1次write100个字节,可能2次50个字节,可能5次20个字节。也就是无法区别对端一次性write的数据量。
针对管道/FIFO数据字节流的特点,在两端必须由应用自定义解释,也就是编制数据传输的协议。
<!--[if !supportLists]-->Ø
<!--[endif]-->FIFO和pipe一样可以以全双工的形式来使用,原理也是一个进程同时打开读和写的文
件描述字,但全双工使用较少,尽量采用半双工形式。
分享到:
相关推荐
它允许进程间通信(IPC),使得数据可以从一个进程写入,另一个进程读出,遵循FIFO规则。 2. **同步和信号量**:在多线程或多进程环境中,为了确保正确访问FIFO,可能需要使用同步机制,如互斥锁(mutex)或信号量...
在IT行业中,FIFO(First In First Out)和管道(PIPE)是进程间通信(IPC,Inter-Process Communication)的两种重要方式。FIFO是一种特殊的文件类型,它遵循先进先出的原则,允许不同进程通过文件系统进行数据交换...
Linux进程间通信之FIFO,适用于任意进程间. 此C文件为FIFO的写端
其中,FIFO(First In First Out)也称为命名管道,是一种简单但有效的 IPC 形式。FIFO 提供了一种半双工通信方式,即数据只能在一个方向上流动,但可以在两个进程中传递。 标题中的"fifo.rar_fifo_fifo lin_fifo ...
在Linux操作系统中,进程间通信(IPC,Inter-Process Communication)是多个进程之间共享数据、交换信息的关键技术。本文将详细讲解如何通过FIFO(First In First Out,先进先出)这种特殊的管道通信机制实现进程间...
在Linux操作系统中,FIFO(First In First Out)是一种特殊的文件类型,也称为命名管道,它提供了一种进程间通信(IPC,Inter-Process Communication)的方式。本压缩包中的源码`wfifo.c`和`rfifo.c`分别展示了如何...
管道通信,也称为命名管道(Named Pipe)或FIFO(First In First Out),是Linux和Unix-like操作系统中的一种进程间通信(IPC, Inter-Process Communication)机制。它允许不同进程之间进行单向或双向的数据传输,...
FIFO是一种特殊的数据结构,广泛应用于操作系统中,特别是在进程间通信(IPC,Inter-Process Communication)时,如管道(pipe)。 描述中提到的"FIFO test code"是用于测试FIFO读写功能的应用程序。这个应用程序...
在操作系统中,FIFO常用于实现进程间通信(IPC)的管道,以及在硬件层面,如内存缓存和I/O设备的数据缓冲。 **同步FIFO** 在多线程或多进程环境中,当两个或更多组件同时访问FIFO时,可能会引发数据竞争和不一致性...
3. **管道通信**:在进程间通信(IPC)中,FIFO(也被称为命名管道)是一种同步通信机制。两个进程可以通过FIFO进行数据交换,数据的读取和写入遵循FIFO规则,即先写入的数据先被读出。 4. **硬件设备**:在硬件...
本文将详细探讨两种常见的IPC机制:pipe(管道)和fifo(无名管道),并结合提供的源码文件"6_pipe"和"6_fifo"进行深入解析。 1. **管道(Pipe)** - **概念**:管道是一种半双工的通信方式,允许数据在一个方向上...
在操作系统中,FIFO通常用于进程间的通信(IPC,Inter-Process Communication)。例如,通过创建命名管道(named pipe),两个或多个进程可以共享一个FIFO数据流进行数据传输。在Windows系统中,这可以通过创建FILE_...
在操作系统中,FIFO也被用作进程间通信(IPC)的一种方式,称为命名管道。在这种情况下,多个进程可以读写同一个FIFO,遵循先进先出的原则。 7. **性能优化**: 对于高性能系统,FIFO可能会设计成流水线式,以...
FIFO,也被称为命名管道,是一种简单的IPC形式,其工作原理类似于物理世界的管道,数据按照进入的顺序被取出。在Unix和类Unix系统如Linux中,FIFO是一种特殊的文件类型,可以在不同的进程之间提供单向或双向的数据...
Unix/Linux系统中,FIFO也被称为命名管道,是进程间通信(IPC)的一种机制。两个不相关的进程可以通过同一个FIFO进行数据交换,一个进程写入,另一个进程读取。创建FIFO使用`mkfifo`命令,然后进程通过文件描述符...
命名管道(FIFO)在Linux系统编程中是一种重要的进程间通信(IPC,Inter-Process Communication)机制。它允许两个没有亲缘关系的进程之间进行数据交换,类似于物理世界的管道,数据从一端流入,另一端流出。FIFO是...
- **Unix/Linux系统编程**:包括文件操作、进程间通信(IPC)以及错误处理。 - **FIFO的工作原理**:理解如何使用`mkfifo()`创建管道,以及如何通过`open()`, `read()`, `write()`等函数进行数据交换。 - **TFTP协议...
在进程间通信(IPC,Inter-Process Communication)中,一个进程将数据写入FIFO,另一个进程则读取这些数据。如果读写速度不匹配,FIFO的大小决定了可以存储多少未处理的数据。 2. **Linux中的FIFO**:在Linux系统...
在Linux操作系统中,FIFO(First In First Out)是一种特殊的文件类型,也称为命名管道,它提供了进程间通信(IPC, Inter-Process Communication)的一种方式。C编程中的FIFO操作可以实现不同进程间的同步和数据交换...
在嵌入式Linux系统开发中,FIFO(First In First Out,先进先出)是一种重要的进程间通信(IPC,Inter-Process Communication)机制。标题"fifo.zip_fifo"和描述中的关键词"FIFO"提示我们,这个压缩包包含的是与FIFO...