FIFO
FIFO指代先进先出,first in first out,也称为有名管道。其是一个单向的(半双工)的数据流,每个FIFO有一个路径名与之关联,从而实现无亲缘关系的进程访问同一个FIFO。
FIFO由mkfifo函数创建
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname,mode_t mode);/*pathname 为文件路径名,是FIFO的名字。mode是文件权限位*/
管道与FIFO异同
- 管道只能用于有亲缘关系的进程,FIFO可用于无亲缘关系的进程(FIFO在文件系统中有一个名字)。
- 管道在所有进程最终关闭它之后自动消失。FIFO的名字则只能通过调用unlink才从文件系统中删除。
- 创建并打开管道:pipe
- 创建FIFO:mkfifo 打开FIFO:open
- 对管道或FIFO的write总是向末尾添加数据,read总是从开头返回数据。
实现两个FIFO的客户-服务器例子
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#define FIFO1 "/tmp/fifo.1"
#define FIFO2 "/tmp/fifo.2"
void client(int readfd,int writefd);
void server(int readfd,int writefd);
int main(int argc,char *argv[])
{
int readfd,writefd;
pid_t childpid;
if((mkfifo(FIFO1,FILE_MODE) < 0 ) && (errno != EEXIST))/*创建两个FIFO*/
printf("can not create %s\n",FIFO1);
if((mkfifo(FIFO2,FILE_MODE) < 0 ) && (errno != EEXIST))
{
unlink(FIFO1);
printf("can not create %s\n",FIFO2);
}
if ((childpid = fork()) == 0)/*子进程*/
{
readfd = open(FIFO1,O_RDONLY,0);/*读FIFO1*/
writefd = open(FIFO2,O_WRONLY,0);/*写FIFO2*/
server(feadfd,writefd);
exit(0);
}
/*父进程*/
writefd = open(FIFO1,O_WRONLY,0);/*写FIFO1*/
readfd = open(FIFO2,O_WRONLY,0);/*读FIFO2*/
client(readfd,writefd);
waitpid(childpid,NULL,0);
close(readfd);
close(writefd);
unlink(FIFO1);/*手动删除FIFO1/2*/
unlink(FIFO2);
}
void client(int readfd,int writefd)/*参数分别为 pipe2[0],pipe1[1]*/
{
size_t len;
ssize_t n;
char buff[MAXLEN];
fgets(buff,MAXLEN,stdin);/*从标准输入stdin中获取输入(一段路径名)放入buff*/
len = strlen(buff);
if(buff[len - 1] == '\n') /*删除由fgets存入的换行符*/
len--;
write(writefd,buff,len);/*将buff中内容写入管道pipe1[1] writefd,传输到子进程server*/
while((n = read(readfd,buff,MAXLEN)) > 0)/*从pipe[0] readfd中读取子进程server传输过来的内容放入buff,并显示到标准输出stdout*/
write(STDOUT_FILENO,buff,n);
}
void server(int readfd,int writefd)/*参数对应pipe1[0],pipe2[1]*/
{
int fd;
ssize_t n;
char buff[MAXLEN+1];
if((n = read(readfd,buff,MAXLEN)) == 0)/*从管道pipe1[0] readfd中读取来自父进程client的输入并放入buff*/
printf("end-of-file while reading pathname\n");
buff[n] = '\n';
if((fd = open(buff,O_RDONLY)) < 0)/*open 打开client 通过管道传输过来的路径名*/
{
snprintf(buff+n,sizeof(buff) - n,"can not open %s\n",strerror(errno));
n=strlen(buff);
write(writefd,buff,n);/*打开失败,将错误信息写入管道writefd pipe2[1],传输至父进程client*/
}
else
{
while((n = read(fd,buff,MAXLEN)) > 0)/*打开成功,将路径名对应的文件中的内容读出到buff,
并写到管道writefd pipe2[1] 传输至父进程client */
write(writefd,buff,n);
close(fd);
}
}