牡丹江 网站建设,网上服务旗舰店,上海网络建站模板,旅游网站的建设方式Linux进程间通信-FIFO命名管道
1、概述 管道因为没有名称#xff0c;所以只用于进程间的亲缘通信。为了克服这一缺点#xff0c;提出了命名管道(FIFO)#xff0c;又称命名管道、FIFO文件。 FIFO不同于无名管道#xff0c;它提供与之关联的路径名#xff0c;该路径名以FIF…Linux进程间通信-FIFO命名管道
1、概述 管道因为没有名称所以只用于进程间的亲缘通信。为了克服这一缺点提出了命名管道(FIFO)又称命名管道、FIFO文件。 FIFO不同于无名管道它提供与之关联的路径名该路径名以FIFO文件的形式存在于文件系统中。这样即使进程与FIFO的创建进程没有亲属关系只要能够访问路径就可以通过FIFO相互通信。不相关的过程也可以通过FIFO交换数据。 FIFO 在文件系统中作为一个特殊的文件而存在。虽然FIFO文件存放在文件系统中但是FIFO 中的内容却存放在内存中。当使用 FIFO 的进程退出后FIFO 文件将继续保存在文件系统中以便以后使用。
2、相关函数 一旦创建了一个FIFO就可用open打开它一般的文件访问函数close、read、write等都可用于FIFO。 FIFO在使用的过程中常用到如下函数
函数释意mkfifo创建管道open打开管道read读管道write写管道unlink关闭管道unlink删除管道上述函数中除了mkfifo函数需要注意一下其他的函数全是标准的IO操作接口这里不做解释。使用fifo之前需要使用mkfifo创建一个管道同时会在指定位置创建一个用于描述管道的文件。
#include sys/types.h
#include sys/stat.h
/*
pathnameFIFO文件名
mode属性见文件操作章节
返回值若成功则返回0否则返回-1错误原因存于errno中。
错误代码
EACCESS 参数pathname所指定的目录路径无可执行的权限
EEXIST 参数pathname所指定的文件已存在。
ENAMETOOLONG 参数pathname的路径名称太长。
ENOENT 参数pathname包含的目录不存在
ENOSPC 文件系统的剩余空间不足
ENOTDIR 参数pathname路径中的目录存在但却非真正的目录。
EROFS 参数pathname指定的文件存在于只读文件系统内。
*/
int mkfifo(const char * pathname, mode_tmode)打开管道时默认是阻塞模式写管道时如果没有其他进程读管道写管道就会阻塞住。同理读管道操作也是如此如果没有进程写管道读管道就会被阻塞住。打开管道时以O_NONBLOCK的标志打开fifo文件程序会直接返回不管fifo的对端是什么状态。
3、例程 写入测试程序先判断FIFO文件是否存在如果文件不存在则调用mkfifo创建一个FIFO通道。以OPEN打开FIFO通道调用fgets获取控制台输入的内容使用write方法将数据写入到FIFO通道。
#include errno.h
#include stdlib.h //for exit
#include stdio.h //for printf
#include unistd.h //for close
#include sys/stat.h //for mkfifo
#include fcntl.h //for open
#define FIFO_NUM1 /tmp/fifotest
#define MAX_BUFFER_SIZE 100
int main(int argc, char * argv[])
{/* 判断有名管道是否已存在若尚未创建则以相应的权限创建 */if (access(FIFO_NUM1, F_OK) -1){if ((mkfifo(FIFO_NUM1, 0777) 0) (errno ! EEXIST)){printf(Failed to create fifo file\n);exit(1);}}/* 以只写阻塞方式打开FIFO管道 */int fd open(FIFO_NUM1, O_WRONLY);if (fd -1){printf(Failed to open fifo\n);exit(1);}while(1){char buff[MAX_BUFFER_SIZE] {0};fgets(buff,sizeof(buff),stdin);/* 向管道中写入字符串 */if (write(fd, buff, MAX_BUFFER_SIZE) 0){printf(Write %s to FIFO\n, buff);}}close(fd);exit(0);
}读取测试程序同样先判断FIFO文件是否存在不存在则调用mkfifo创建一个FIFO通道。使用read循环读取FIFO的内容并打印出来。
#include errno.h
#include stdlib.h //for exit
#include stdio.h //for printf
#include unistd.h //for close
#include sys/stat.h //for mkfifo
#include fcntl.h //for open
#define FIFO_NUM1 /tmp/fifotest
#define MAX_BUFFER_SIZE 100
int main(void)
{/* 判断有名管道是否已存在若尚未创建则以相应的权限创建 */if (access(FIFO_NUM1, F_OK) -1){if ((mkfifo(FIFO_NUM1, 0777) 0) (errno ! EEXIST)){printf(Failed to create fifo file\n);exit(1);}}/* 以只读阻塞方式打开有名管道 */int fd open(FIFO_NUM1, O_RDONLY);if (fd -1){printf(Failed to open fifo\n);exit(1);}while (1){char buff[MAX_BUFFER_SIZE] {0};if (read(fd, buff, MAX_BUFFER_SIZE) 0){printf(Read %s from fifo\n, buff);}}close(fd);exit(0);
}使用gcc分别编译文件然后直接调用就可以运行了。可以看到运行结果与预期一致。
$ gcc ./write.c -o write
$ ./write
11
Write 11to FIFO
222
Write 222to FIFO
333
Write 333to FIFO
444
Write 444to FIFO$ gcc ./read.c -o read
$ ./read
Read 11from fifo
Read 222from fifo
Read 333from fifo
Read 444from fifo
4、题外话 FIFO管道在创建时会锁定文件的权限。我上面写的例程创建FIFO时写入的是0777的权限实际生成的FIFO文件却是755的权限。也就是说FIFO文件只有创建者有权限读写其他成员只能读取不能执行写入的动作。
$ ls -l /tmp/fifotest
prwxr-xr-x 1 zac zac 0 Nov 18 16:40 /tmp/fifotest如果有两个应用之间通过FIFO通信但两个应用属于不同的用户。这时候读取进程按照上面所说的例程方式先启动创建了FIFO文件。那么等写入进程运行起来后将无法进行FIFO管道的写入操作。 这时候读取进程需要做出一些小修改。可以每隔一段时间查询一下FIFO文件的状态等待写入进程成功创建FIFO文件。 xxxxxx/* 判断有名管道是否已存在若尚未创建则等待片刻*/while(access(FIFO_NUM1, F_OK) -1){usleep(200*1000);}xxxxxx5、总结
要创建和打开管道只需调用pipe。创建和打开一个FIFO在调用mkfifo后还需要使用open;管道在所有进程最终关闭后自动消失只有通过调用unlink才能从文件系统中删除FIFO名称。创建FIFO文件时会锁定文件的写入权限只有创建者才有资格写入