进程间通信:命名管道FIFO(2)
一、命名管道
如果我们想在不相关的进程之间交换数据,可以用FIFO文件来完成这项工作,它通常也被称为命名管道。命名管道是一种特殊类型的文件,它在文件系统中以文件名的形式存在,但是它的行为却和我们已经见过的没有名字的管道类似。我们可以在命令行上创建命名管道,也可以在程序中创建它。
命名管道(FIFO)和无名管道(pipe)有一些特点是相同的,不一样的地方在于:
1、FIFO 在文件系统中作为一个特殊的文件而存在,但 FIFO 中的内容却存放在内存中。
2、当使用 FIFO 的进程退出后,FIFO 文件将继续保存在文件系统中以便以后使用。
3、FIFO 有名字,不相关的进程可以通过打开命名管道进行通信。
1、FIFO的创建
- #include<sys/types.h>
- #include<sys/stst.h>
- int mkfifo(const char *filename,mode_t mode);
pathname: 普通的路径名,也就是创建后 FIFO 的名字,mode: 文件的权限,与打开普通文件的 open() 函数中的 mode 参数相同,返回值为0,代表FIFO创建成功。
2、命名管道的默认操作
后期的操作,把这个命名管道当做普通文件一样进行操作:open()、write()、read()、close()。但是,和无名管道一样,操作命名管道肯定要考虑默认情况下其阻塞特性。
下面验证的是默认情况下的特点,即 open() 的时候没有指定非阻塞标志( O_NONBLOCK )。
1)open() 以只读方式打开 FIFO 时,要阻塞到某个进程为写而打开此 FIFO;
open() 以只写方式打开 FIFO 时,要阻塞到某个进程为读而打开此 FIFO。
简单一句话,只读等着只写,只写等着只读,只有两个都执行到,才会往下执行。
只读端代码如下:
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- int main(int argc, char *argv[])
- {
- int fd;
- int ret;
- ret = mkfifo("my_fifo", );
- if(ret != )
- {
- perror("mkfifo");
- }
- printf("before open\n");
- fd = open("my_fifo", O_RDONLY);//等着只写
- if(fd < )
- {
- perror("open fifo");
- }
- printf("after open\n");
- return ;
- }
只写端代码如下:
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- int main(int argc, char *argv[])
- {
- int fd;
- int ret;
- ret = mkfifo("my_fifo", );
- if(ret != )
- {
- perror("mkfifo");
- }
- printf("before open\n");
- fd = open("my_fifo", O_WRONLY); //等着只读
- if(fd < )
- {
- perror("open fifo");
- }
- printf("after open\n");
- return ;
- }
在两个终端分别运行只读和只写程序,会出现阻塞现象,两个程序都要等待彼此,当两者都执行了,才会完成,如下:
- wanh@wanh-VirtualBox:~/linux_c_driver/Demo/pipe$ ./fifo11 //只读端
- mkfifo: File exists
- before open
- after open
- wanh@wanh-VirtualBox:~/linux_c_driver/Demo/pipe$
- wanh@wanh-VirtualBox:~/linux_c_driver/Demo/pipe$ ./fifo22 //只写端
- mkfifo: File exists
- before open
- after open
- wanh@wanh-VirtualBox:~/linux_c_driver/Demo/pipe$
如果不想在 open() 的时候阻塞,我们可以以可读可写方式打开 FIFO 文件,这样 open() 函数就不会阻塞。
- // 可读可写方式打开
- int fd = open("my_fifo", O_RDWR);
2)假如 FIFO 里没有数据,调用 read() 函数从 FIFO 里读数据时 read() 也会阻塞。这个特点和无名管道是一样的。
3)通信过程中若写进程先退出了,就算命名管道里没有数据,调用 read() 函数从 FIFO 里读数据时不阻塞;若写进程又重新运行,则调用 read() 函数从 FIFO 里读数据时又恢复阻塞。
对于(3)读端代码如下:
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- int main(int argc, char *argv[])
- {
- int fd;
- int ret;
- ret = mkfifo("my_fifo", );// 创建命名管道
- if(ret != )
- {
- perror("mkfifo");
- }
- fd = open("my_fifo", O_RDONLY);// 等着只写
- if(fd < )
- {
- perror("open fifo");
- }
- while()
- {
- char recv[] = {};
- read(fd, recv, sizeof(recv)); // 读数据
- printf("read from my_fifo buf=[%s]\n",recv);
- sleep();
- }
- return ;
- }
写端代码如下:
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- int main(int argc, char *argv[])
- {
- int fd;
- int ret;
- ret = mkfifo("my_fifo", ); // 创建命名管道
- if(ret != )
- {
- perror("mkfifo");
- }
- fd = open("my_fifo", O_RDWR); // 等着只读
- if(fd < )
- {
- perror("open fifo");
- }
- char send[] = "Hello Mike";
- //while(1){
- write(fd, send, strlen(send)); //写数据
- printf("write to my_fifo buf=%s\n",send);
- //sleep(1);
- //}// 阻塞,保证读写进程保持着通信过程
- while();
- return ;
- }
当两者执行后,读端读到数据后,由于写端没有继续写入数据,因而读端会阻塞,当写端退出后,读端将不停运行,读到空数据,当写端再次运行,读端将读完数据后再次阻塞;
写端运行情况如下:
- wanh@wanh-VirtualBox:~/linux_c_driver/Demo/pipe$ ./fifo3
- mkfifo: File exists
- write to my_fifo buf=Hello Mike
- ^C
- wanh@wanh-VirtualBox:~/linux_c_driver/Demo/pipe$ ./fifo3
- mkfifo: File exists
- write to my_fifo buf=Hello Mike
读端运行情况如下:
- wanh@wanh-VirtualBox:~/linux_c_driver/Demo/pipe$ ./fifo4
- mkfifo: File exists
- read from my_fifo buf=[Hello Mike]
- read from my_fifo buf=[]
- read from my_fifo buf=[]
- read from my_fifo buf=[]
- read from my_fifo buf=[]
- read from my_fifo buf=[]
- read from my_fifo buf=[]
- read from my_fifo buf=[]
- read from my_fifo buf=[Hello Mike]
5)通信过程中,读进程退出后,写进程向命名管道内写数据时,写进程也会(收到 SIGPIPE 信号)退出。
6)调用 write() 函数向 FIFO 里写数据,当缓冲区已满时 write() 也会阻塞。
3、命名管道非阻塞标志操作
命名管道可以以非阻塞标志(O_NONBLOCK)方式打开:
- fd = open("my_fifo", O_WRONLY|O_NONBLOCK);
- fd = open("my_fifo", O_RDONLY|O_NONBLOCK);
非阻塞标志(O_NONBLOCK)打开的命名管道有以下特点:
1、先以只读方式打开,如果没有进程已经为写而打开一个 FIFO, 只读 open() 成功,并且 open() 不阻塞。
2、先以只写方式打开,如果没有进程已经为读而打开一个 FIFO,只写 open() 将出错返回 -1。
3、read()、write() 读写命名管道中读数据时不阻塞。
写端代码如下:
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- int main(int argc, char *argv[])
- {
- int fd;
- int ret;
- ret = mkfifo("my_fifo", ); // 创建命名管道
- if(ret != )
- {
- perror("mkfifo");
- }
- // 只写并指定非阻塞方式打开
- fd = open("my_fifo", O_WRONLY|O_NONBLOCK);
- if(fd<)
- {
- perror("open fifo");
- }
- char send[] = "Hello Mike";
- write(fd, send, strlen(send));
- printf("write to my_fifo buf=%s\n",send);
- while();
- return ;
- }
读端代码如下:
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- int main(int argc, char *argv[])
- {
- int fd;
- int ret;
- ret = mkfifo("my_fifo", ); // 创建命名管道
- if(ret != )
- {
- perror("mkfifo");
- }
- // 只读并指定非阻塞方式打开
- fd = open("my_fifo", O_RDONLY|O_NONBLOCK);
- if(fd < )
- {
- perror("open fifo");
- }
- while()
- {
- char recv[] = {};
- read(fd, recv, sizeof(recv));
- printf("read from my_fifo buf=[%s]\n",recv);
- sleep();
- }
- return ;
- }
进程间通信:命名管道FIFO(2)的更多相关文章
- 进程间通信系列 之 命名管道FIFO及其应用实例
进程间通信系列 之 概述与对比 http://blog.csdn.net/younger_china/article/details/15808685 进程间通信系列 之 共享内存及其实例 ...
- Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)
整理自网络 Unix IPC包括:管道(pipe).命名管道(FIFO)与信号(Signal) 管道(pipe) 管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道 ...
- 进程间通信___命名管道(FIFO)
命名管道(FIFO) 基本概念 命名管道和一般的管道基本相同,但也有一些显著的不同: 命名管道是在文件系统中作为一个特殊的设备文件而存在的. 不同祖先的进程之间可以通过管道共享数据. 当共享管道的进程 ...
- Linux学习笔记25——命名管道(FIFO)
1 命名管道(FIFO) 管道应用的一个重大缺陷就是没有名字,因此只能用于亲缘进程之间的通信.后来从管道为基础提出命名管道(named pipe,FIFO)的概念,该限制得到了克服.FIFO不同于管道 ...
- 命名管道FIFO及其读写规则
一.匿名管道的一个限制就是只能在具有共同祖先的进程间通信命名管道(FIFO):如果我们想在不相关的进程之间切换数据,可以使用FIFO文件来做这项工作注意:命名管道是一种特殊类型文件.利用命令:$ mk ...
- Linux进程间通信-命名管道
前面我们讲了进程间通信的一种方式,匿名管道.我们知道,匿名管道只能用于父子关系的进程之间.那么没有这种关系的进程之间该如何进行数据传递呢? 1.什么是命名管道 匿名管道是在缓存中开辟的输出和输入文件流 ...
- 命名管道FIFO
首先我得检讨一下自己,这几天有些颓呀,打不起精神,板子出了点问题,果真自学还是很困难呀,硬件方面难解决呀,理想与现实还是很有差距的,伤透了,凌乱了. 一直在理解进程间通信的问题.发现上次忽略了一个问题 ...
- 命名管道FIFO和mkfifo函数
进程间通信必须通过内核提供的通道,而且必须有一种办法在进程中标识内核提供的某个通道,前面讲过的匿名管道是用打开的文件描述符来标识的.如果要互相通信的几个进程没有从公共祖先那里继承文件描述符,它们怎么通 ...
- Linux - 进程间通信 - 命名管道
1.命名管道的特点: (1)是管道,可用于非血缘关系的进程间的通信 (2)使用命名管道时,梁金成需要用路径表示通道. (3)命名管道以FIFO的文件形式存储于文件系统中.(FIFO:总是按照先进先出的 ...
随机推荐
- sublime text3配置python开发环境(windows版)
安装阶段: sublime text3的安装: 下载网址:https://www.sublimetext.com/ 下载完成后 ,点击安装即可. 安装Package Control: 点击 Tools ...
- 【Java】集合概述Collection、Map
Java集合分为Collection和Map,Collection又分为List.Set. List中有ArrayList.LinkedList和Vector:Set中又分为HashSet和TreeS ...
- WIN10下WNMP开发环境部署
刚刚开始学习PHP时,一直使用phpstudy,后面发现很多东西自己单独配置安装会理解更深刻,所以自己总结了一下windows下开发环境的部署教程. 以前经常在CSDN和博客园看别人的教程,今天才注册 ...
- Nginx 负载均衡搭建
配置文件Nginx/conf/nginx.conf 什么是负载均衡呢? 由于目前现有网络的各个核心部分随着业务量的提高,访问量和数据流量的快速增长,其处理能力和计算强度也相应地增大,使得单一的服务器设 ...
- Hbase过滤器
Hbase过滤器简介 HBase的基本API,包括增.删.改.查等,增.删都是相对简单的操作,与传统的RDBMS相比,这里的查询操作略显苍白,只能根据特性的行键进行查询(Get)或者根据行键的范围来查 ...
- 『Python题库 - 简答题』 Python中的基本概念 (121道)
## 『Python题库 - 简答题』 Python中的基本概念 1. Python和Java.PHP.C.C#.C++等其他语言的对比? 2. 简述解释型和编译型编程语言? 3. 代码中要修改不可变 ...
- Java学习笔记十六:Java中的构造方法
Java中的构造方法 1.使用new+构造方法 创建一个新的对象: 2.构造方法是定义在Java类中的一个用来初始化对象的方法: 3.构造方法与类同名且没有返回值: 4.语法格式: public 构造 ...
- 北京Uber优步司机奖励政策(1月21日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- ORB-SLAM(十)LoopClosing Sim3求解
主要参考这篇论文 Horn B K P. Closed-form solution of absolute orientation using unit quaternions[J]. JOSA A, ...
- 如何利用Navicat导入/导出mssql中的数据
sqlserver,在第一次使用该软件进行"连接"的时候,会提示安装"Microsoft Sqlsever Navicat Client.",这时直接点击&qu ...