有名管道又称为FIFO,是进程间通信的一种方式。FIFO具有以下特点:
1.全双工的通信模式,数据先进先出;
2.可以用于任意的进程之间,通过指定相同的管道文件进行通信;
3.文件名存在文件系统中,而管道中的内容存在于内存中。可通过open、read、write对其操作;
有名管道的总体操作:
创建管道mkfifo
打开管道open
读管道read
写管道write
关闭管道close
删除管道unlink
创建:
头文件
#include <sys/types.h>
#include <sys/stat.h>
函数原型:
int mkfifo(const char * pathname, mode_t mode)
函数参数:
pathname:FIFO文件名
mode:同open类似。
返回值:成功0,出错-1
一旦创建了一个FIFO,就可用open打开它,一般的文件访问函数(close、read、write等)都可用于FIFO
FIFO文件在使用上和普通文件有相似之处,但是也有不有
不同之处:
1. 读取fifo文件的进程只能以”RDONLY”方式打开fifo文件。
2. 写fifo文件的进程只能以”WRONLY”方式打开fifo
3. fifo文件里面的内容被读取后,就消失了。但是普通文件里面的内容读取后还存在。
其他的都和文件操作一样,这里不在重复赘述。
下面我们来看看例题:
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FIFO "/tmp/myfifo"
main(int argc,char** argv)
{
char buf_r[100];
int fd;
int nread;
/* 创建管道 */
if((mkfifo(FIFO,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST))
printf("cannot create fifoserver\n");
printf("Preparing for reading bytes...\n");
memset(buf_r,0,sizeof(buf_r));
/* 打开管道 */
fd=open(FIFO,O_RDONLY|O_NONBLOCK,0);
if(fd==-1)
{
perror("open");
exit(1);
}
while(1)
{
memset(buf_r,0,sizeof(buf_r));
if((nread=read(fd,buf_r,100))==-1)
{
if(errno==EAGAIN)
printf("no data yet\n");
}
printf("read %s from FIFO\n",buf_r);
sleep(1);
}
pause(); /*暂停,等待信号*/
unlink(FIFO); //删除文件
}
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FIFO_SERVER "/tmp/myfifo"
main(int argc,char** argv)
{
int fd;
char w_buf[100];
int nwrite;
/*打开管道*/
fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0);
if(argc==1)
{
printf("Please send something\n");
exit(-1);
}
strcpy(w_buf,argv[1]);
/* 向管道写入数据 */
if((nwrite=write(fd,w_buf,100))==-1)
{
printf("The FIFO has not been read yet.Please try later\n");
}
else
printf("write %s to the FIFO\n",w_buf);
}
需要注意的是,调用 open() 打开有名管道的进程可能会被阻塞。但如果同时以读写方式 ( O_RDWR ) 打开,则一定不会导致阻塞;如果以只读方式 ( O_RDONLY ) 打开,则调用 open() 函数的进程将会被阻塞直到有写方打开管道;同样以写方式 ( O_WRONLY ) 打开也会阻塞直到有读方打开管道。
1. 在用open打开FIFO时有可能会阻塞,原因就是当前只有读端或写端存在。换句话说,如果程序在打开FIFO时指定了只读方式/只写方式,那么该进程对于打开的FIFO来说就是一个读端/写端。如果指定的是读写方式,那么进程即是读端又是写端。
2. 从FIFO中读数据时(用read函数),如果没有数据,默认是阻塞等待,直到有数据被写入FIFO。如果read函数返回0,说明该FIFO所有的写端都已关闭,程序要做相应的处理。向FIFO写入数据时(使用write函数),如果FIFO有足够空间,write函数会返回写入的字节数;如果空间不够,write函数会阻塞,直到写完为止。当所有的读端都关闭时,再向FIFO写数据会出错。内核会向写进程发管道断裂的信号(SIGPIPE), 从而终止该进程。处理的办法有两种:程序以读写方式打开FIFO或是在程序中捕捉SIGPIPE信号,由用户自行处理。