linux下的FIFO机制

linux下的一切操作都是文件操作,而FIFO操作也是其中的一类文件操作,想要了解FIFO操作的原理,首先需要了解管道的原理。

管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常说的管道多是指无名管道,无名管道只能用于具有亲缘关系的进程之间,这是它与有名管道的最大区别。管道实现的源代码在fs/pipe.c中,在pipe.c中有很多函数,其中有两个函数比较重要,即管道读函数pipe_read()和管道写函数pipe_wrtie()。

了解管道,从下面这个例程开始:linux进程间通信之管道

#include 
#include 
#include 
#include  

int main(void)
{
	int fds[2];	//两个文件描述符,用以表示:写入方fd==PIPE==读取方,fds[0]用于读出数据,读取时必须关闭写入端,即close(fds[1]);fds[1]用于写入数据,写入时必须关闭读取端,即close(fds[0])
	if(pipe(fds) == -1){	//pipe(fds)是指建立管道获取到一对文件描述符,建立成功返回0,建立失败返回-1
		perror("pipe error");
		exit(EXIT_FAILURE);
	}
	pid_t pid;
	pid = fork();//父进程将文件描述符复制给子进程
	if(pid == -1){
		perror("fork error");
		exit(EXIT_FAILURE);
	}
	if(pid == 0){//子进程写
		close(fds[0]);//子进程关闭读端
		sleep(10);
		write(fds[1],"hello",5);
		exit(EXIT_SUCCESS);
	}else//父进程要读管道中的内容
	close(fds[1]);//父进程关闭写端
	char buf[10] = {0};
	read(fds[0],buf,10);//父进程读
	printf("receive datas = %s\n",buf);
	return 0;
}
由此可见,管道的运行过程依靠一对文件描述符,于是存在单发单收的情况,双方呈现出父子进程配对的状态,为此,FIFO提出解决了单发单收的问题,以FIFO文件的位置作为介质,两个进程可以对FIFO文件完成对应的读写操作。由于可能会有多个线程同时争取读写的权利,因此,FIFO引入了阻塞的概念:

若带阻塞的读取,则需要等待有写入才能引发中断完成该操作,否则将阻塞FIFO的输出一直等待;不带阻塞的读取在FIFO文件为空时则将返回0的结果;

若带阻塞的写入,则要求必须以原子操作为单位进行写入,争取一次性写完;由于每次写入的存在上限,若小于上限,则一次性完成,若大于上限,等待下一次空闲的缓冲区域继续写入,写完再返回;不带阻塞的写入则只写一次,缓冲区域一次能写完,返回写入字节数,一次不能写完,返回错误,提醒下次再写;

FIFO管道例程:FIFO系统编程之命名管道(FIFO) 此中为经典例程,通过FIFO管道完成文件的复制
FIFO管道依赖于文件描述符(fd),正常的FIFO使用过程为:

1)建立FIFO管道mkfifo(name,mode):mkfifo函数 (注意:头文件不能忘掉)

2)打开FIFO管道open(name,mode);FIFO的打开与读写规则

3)读bytes_write = write(to_fd, ptr, bytes_read)或写bytes_read = read(from_fd, buffer, BUFFER_SIZE); linux下文件的读写操作

现贴出文件复制的代码,由于针对固定FIFO管道,因此在读取的时候将FIFO管道的名称作为第三个参数,第二个参数仍然为读取后得到的文件名称;同时附程序下载渠道:(FIFO读写文件)

创建打开FIFO并将文件中的字符串写入FIFO:

#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char **argv)
{
    if(argc != 2){
        fprintf(stderr,"usage:%s srcfile\n",argv[0]);
        exit(EXIT_FAILURE);
    }
    int infd;
    infd = open(argv[1],O_RDONLY);
    if(infd == -1){
        perror("open error");                                                                                                               
        exit(EXIT_FAILURE);
     }
     if(mkfifo("tmpfifo",0644) == -1){
        perror("mkfifo error");
        exit(EXIT_FAILURE);
     }
     int fd ;
     fd = open("tmpfifo",O_WRONLY);
     if(fd == -1){
         perror("open error");
         exit(EXIT_FAILURE);
     }
     char buf[1024*4];
     int n = 0;
     while((n = read(infd,buf,1024*4))){
        write(fd,buf,n);
     }
     close(infd);
     close(fd);
     printf("write success\n");
     return 0;
} 
打开FIFO读取FIFO中的字符串,放入新文件中:

#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char **argv)
{
	if(argc != 3){
		fprintf(stderr,"usage:%s desfile\n",argv[0]);
		exit(EXIT_FAILURE);
	}
	int outfd;
	outfd = open(argv[1],O_WRONLY|O_CREAT|O_TRUNC);
	if(outfd == -1){
		perror("open error");
		exit(EXIT_FAILURE);
	}
	int fd ;
	fd = open(argv[2],O_RDONLY);
	if(fd == -1){
		perror("open error");
		exit(EXIT_FAILURE);
	}
	char buf[1024*4];
	int n = 0;
	while((n = read(fd,buf,1024*4))){
		write(outfd,buf,n);
	}
	close(fd);
	close(outfd);
	unlink(argv[2]);
	printf("read success\n");
	return 0;
}



你可能感兴趣的:(Linux)