使用命名管道的操作和使用普通的文本文件类似,都是系统调用open函数去打开创建好的管道,使用read,write函数操作,操作完成后用close函数关闭。
从FIFO中读取数据的规则是:
1,如果一个进程为了从fifo中读取数据而阻塞打开fifo,n那么称该进程内的读操作为设置了阻塞标志的读操作。
2,如果有进程写打开了fifo,而且当前fifo内没有数据,则对于这于设置了阻塞标志的读操作来说,将一直阻塞,对于没有设置阻塞标志读操作来说则返回-1,当前errno值为EGIN,提醒以后再试。
3,对于设置阻塞标志的读操作来说,造成阻塞的原因有两种:① 当前fifo内有数据,但有其他的进程在读这些数据。②fifo里面没有数据。解阻塞的原因则是fifo有新的数据写入不管新写入数据量的大小,也不论读操作请求多少数据。
4,读打开的阻塞标志只对本进程第一个读操作施加作用,如果本进程内有多个读操作序列,则在第一个读操作被唤醒并完成读操作后,其他要执行的读操作将不再阻塞。即使在执行读操作时,fifo里面没有数据也一样(读操作返回0)。
5,如果没有写进程打开fifo,则设置了阻塞标志的读操作也会阻塞。
向fifo中写入数据的规则是:
1.如果一个进程为了向fifo中写数据而阻塞打开fifo,那么称该进程内的写操作为设置了阻塞标志的写操作。
2.对于设置了阻塞标志的写操作,当要写入的数据量不大于PIPE_BUF时,Linux将保证写入的原子性,如果此时管道空闲缓冲区不足以容纳要写入的数据时,则进入睡眠,知道当缓冲区能够容下要写入数据字节数时,才开始进行一次性写操作。
3.当要写入的数据量大于PIPE_BUF时,linux不能保证写入的原子性,在写满fifo空闲缓冲区后,写操作返回。
4.要写入的数据量不大于PIPE_BUF时,linux将保证写入原子性,如果当前缓冲区能容下要写的数据,则写完后返回,相反的话,返回EAGIN错误,提醒以后再写。
write_fifo.c: #include<sys/types.h> #include<sys/stat.h> #include<stdio.h> #include<fcntl.h> #include<unistd.h> #include<limits.h> #include<stdlib.h> #include<time.h> #define BUFES PIPE_BUF int main(void) { int fd; int n,i; char buf[BUFES]; time_t tp; printf("%d\n",getpid()); if((fd=open("fifo1",O_WRONLY))<0) { printf("open failed\n"); exit(1); } for(i=0;i<10;i++) { time(&tp); n=sprintf(buf,"write fifo %d sends %s",getpid(),ctime(&tp)); printf("send msg:%s\n",buf); if((write(fd,buf,n+1))<0) { printf("write failed!\n"); close(fd); exit(1); } sleep(3); } close(fd); exit(0); }
read_fifo.c #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<stdlib.h> #include<stdio.h> #include<limits.h> #include<fcntl.h> #define BUFES PIPE_BUF int main(void) { int fd; int len; char buf[BUFES]; mode_t mode =0666; if((fd=open("fifo1",O_RDONLY))<0) { printf("Open failed"); exit(1); } while((len=read(fd,buf,BUFES))>0) { printf("Read_fifo read:%s\n",buf); } close(fd); exit(0); return 0; }
Step 1: lishun@lishun-Qt:~$ mkfifo -m 0666 fifo1 (建立管道)
Step2: gcc write_fifo.c -o write
Ste2: ./write (write 当前 阻塞,一直到运行read)
Step3: gcc read_fifo.c -o read
Step4: ./read