每个FIFO都有一个路径与之相关联,从而允许无亲缘关系的进程间通信.
FIFO相关的函数:
#include<sys/types.h>
#include<sys/stat.h>
int mkfifo(const char* pathname,mode_t mode); //错误返回-1
此函数的作用为:使pathname与所创建的FIFO相关联,打开FIFO就用open函数打开路径pathname
FIFO的读写就是通过open函数返回的文件描述来操作
管道和FIFO需要注意的地方就是它们分别在什么地方阻塞
当前操作 | 管道或FIFO的现有操作 | 阻塞返回(默认) | 设置O_NONBLOCK返回 |
open FIFO 只读 | FIFO打开来写 | 成功返回 | 成功返回 |
FIFO不是打开来写 | 阻塞到FIFO打开来写 | 成功返回 | |
open FIFO 只写 | FIFO打开读 | 成功返回 | 成功返回 |
FIFO不是打开来读 | 阻塞到FIFO打开来读 | 返回ENXIO错误 | |
从空管道或FIFO read | 管道或FIFO打开来写 | 阻塞到管道或FIFO中有数据或者管道或FIFO 不再为写打开着为止 | 返回EAGAIN错误 |
管道或FIFO不是打开来写 | read 返回0(文件结束符) | read 返回0(文件结束符) | |
往管道或FIFO write | 管道或FIFO打开来读 | 分情况 | 分情况 |
管道或FIFO不是打开来读 | 给线程产生SIGPIPE | 给线程产生SIGPIPE |
注意上面表格中当管道或FIFO已有一端打开读时,此时往管道或FIFO中写入数据时,存在如下限制:
1,如果请求写入的数据的字节数小于或等于PIPE_BUF,则写入操作是原子的,不存在两个进程同时写.
但当大于PIPE_BUF时,就不能保证原子性,可能存在交叉写的可能.
2,如果待写入的字节数小于PIPE_BUF,要写入的数据在管道中还有足够的空间存放,则所有数据都写入
3,如果待写入的字节数小于PIPE_BUF,该管道或FIFO中没有足够的空间存放要写入的数据,则立即返回EAGAIN
4,如果待写入的字节数大于PIPE_BUF,且管道或FIFO中还有剩余空间,则只写入部分数据,使管道或FIFO写满.
5,如果待写入的字节数大于PIPE_BUF,且管道或FIFO已满,则返回EAGAIN
6,如果向一个没有为读打开着的管道或FIFO写入,那么内核将产生一个SIGPIPE信号
a)如果调用进程没有捕获也没有忽略该信号,默认就是终止该进程
b)如果调用进程忽略该信号或者捕获了该信号并从其信号处理程序中返回,那么write返回一个EPIPE错误.
一下是利用FIFO写的服务器端和客户端代码:
服务器端:FIFO_server.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO_SERVER "fifo.server"
#define FIFO_CLIENT "fifo.client"
#define MAXLINE 512
int main(int argc,char *argv[])
{
int fd_read;
int fd_write;
int fd_dump;
int res;
int fd;
char buf[MAXLINE+1];
memset(buf, '\0', sizeof(buf));
//验证有名管道文件存不存在
if (access(FIFO_SERVER, F_OK) == -1)
{
printf("创建有名管道FIFO:\n");
res = mkfifo(FIFO_SERVER, 0766);
if (res != 0)
{
fprintf(stderr, "Could not create fifo %s\n", FIFO_SERVER);
exit(EXIT_FAILURE);
}
}
printf("Process %d opening FIFO O_WRONLY\n", getpid());
fd_read = open(FIFO_SERVER,O_RDONLY); //以读方式打开管道
fd_dump = open(FIFO_SERVER, O_WRONLY); //以写方式打开管道
printf("the file's descriptor is %d\n", fd_read);
int n = 0;
while((n = read(fd_read,buf,MAXLINE)) > 0)
{
/*
if(buf[n-1] == '\n')
n--;
buf[n] = '\0'
*/
//打开从管道中读出来的文件路径
printf("从管道中读到%d字节数据:%s\n",n,buf);
if((fd_write = open(FIFO_CLIENT,O_WRONLY)) < 0)
{
printf("不能打开客户端的FIFO文件!\n");
continue;
}
printf("打开文件读取数据:\n");
if((fd = open(buf,O_RDONLY)) < 0) //打开错误就将错误信息写入到客户端管道
{
snprintf(buf+n,sizeof(buf) - n,": 不能打开!,%s\n",strerror(errno));
n = strlen(buf);
write(fd_write,buf,n);
close(fd_write);
}
else
{
memset(buf, '\0', sizeof(buf));
while((n = read(fd,buf,MAXLINE)) > 0)
{
write(fd_write,buf,n);
}
printf("将文件的数据读完,且全部写入管道!\n");
close(fd);
close(fd_write);
}
}
unlink(FIFO_SERVER);
printf("Process %d finished\n", getpid());
exit(EXIT_SUCCESS);
}
客户端:FIFO_client.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO_SERVER "fifo.server"
#define FIFO_CLIENT "fifo.client"
#define MAXLINE 512
int main(int argc,char *argv[])
{
int fd_read;
int fd_write;
int res;
char buf[MAXLINE+1];
memset(buf, '\0', sizeof(buf));
//验证有名管道文件存不存在
if (access(FIFO_CLIENT, F_OK) == -1)
{
printf("创建有名管道FIFO:\n");
res = mkfifo(FIFO_CLIENT, 0766);
if (res != 0)
{
fprintf(stderr, "Could not create fifo %s\n", FIFO_CLIENT);
exit(EXIT_FAILURE);
}
}
printf("Process %d opening FIFO O_RDONLY\n", getpid());
fd_write = open(FIFO_SERVER,O_WRONLY); //以只写的方式打开服务器端的FIFO
res = write(fd_write,argv[1],strlen(argv[1]));
printf("读出的文件路径大小为:%d\n",res);
if(res != strlen(argv[1])) //将文件路径写入到服务器端管道
{
printf("将文件路径写入服务器端FIFO失败!\n");
unlink(FIFO_CLIENT);
exit(EXIT_FAILURE);
}
fd_read = open(FIFO_CLIENT, O_RDONLY); //用读方式打开客户端管道
printf("the file's descriptor is %d\n",fd_read);
int n;
while( (n = read(fd_read, buf, MAXLINE)) > 0) //从管道中读出数据
{
// printf("从管道中读出的数据大小为:%d\n",n);
write(STDOUT_FILENO,buf,n);
memset(buf, '\0', sizeof(buf));
}
close(fd_read);
unlink(FIFO_CLIENT);
printf("Process %d finished\n", getpid());
exit(EXIT_SUCCESS);
}
测试用的文件:test
sdfhidhsfuh
fjdsihjfidsh
243254
fjdsi13213
输出结果:
首先运行服务器端:
[tsj@********* ch09 16:30]$gcc -o FIFO_server FIFO_server.c
[tsj@********* ch09 16:31]$./FIFO_server
创建有名管道FIFO:
Process 24940 opening FIFO O_WRONLY
the file's descriptor is 3
从管道中读到4字节数据:test
打开文件读取数据:
将文件的数据读完,且全部写入管道!
客户端:
[tsj@********* ch09 16:31]$gcc -o FIFO_client FIFO_client.c
[tsj@********* ch09 16:31]$./FIFO_client test
创建有名管道FIFO:
Process 25120 opening FIFO O_RDONLY
读出的文件路径大小为:4
the file's descriptor is 4
sdfhidhsfuh
fjdsihjfidsh
243254
fjdsi13213
Process 25120 finished
[tsj@********* ch09 16:31]$