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;
}