前言说明:

宿主主机系统:window 7 旗舰版

虚拟机:VMware 10.0.4

操作平台:Ubuntu 12.04

本文代码在个人电脑可以运行,不确保在其他平台可以正确运行

这两天在学进程通信,学到管道通信,弄了有两天,今天才算能弄个明白,赶紧写来保存方便然后查看,如果能帮到大家就更好了。

1、介绍:管道文件是linux下的一种特殊缓存文件(linux的文件其实都是对应底层的一种设备,管道文件和普通文件,一般对应的是我们的磁盘设备)所谓缓存就是只会存在于进程执行的时候,进程关闭管道文件也关闭了,这与普通文件不一样,普通文件会一直存在的。管道文件是linux特有的,windows下是没有的,所以当你在linux的共享目录下建立管道文件是不可行的(特别注意,管道文件没有文件后缀,里面也没有保留东西,她就好像是自来水管,这一刻流进去的,下一秒就会流出来,不会停留在里面的)

管道文件分为有名管道和无名管道。

无名管道:是指没有文件节点的管道文件,只能用于有亲缘关系的进程间的通信

有名管道:是指有文件节点的管道文件,能用于没有亲缘关系和有亲缘关系的进程间的通信

划重点:什么是文件节点(看的很多博客都没有说到这个问题提一下)

linux下的管道文件是一种树形结构的,树形结构我们都知道,要找到当前内容的下一个内容我们需要知道一个根节点,通过根节点来遍历找到下一个对象。而我们上面说的文件加点就是这个根节点。因为无名管道没有根节点,要想找到一个对象,必须直接找到她,或者通过其中的亲缘关系找到她,就好比如,你跟你父亲之间不需要第三个中间的人就可以直接认识通信一样。(关于无名管道会专门写一篇blog,这里主要介绍有名管道)

有名管道有文件节点的意思即是说,两个进程不需要任何关系也可以通信,因为他们有节点联系,可以通过节点遍历找到需要通信的两个进程,然后进行通信。这个关系就好比如,你跟我认识,但是我不认识你朋友,我跟你的朋友交流我需要通过你这个节点来找到你朋友,才能建立通信。

2、创建有名管道

mkfifo函数

头文件

#include<sys/types.h>

#include<sys/stat.h>

原型

int mkfifo(const char *pathname, mode_t mode)

成功返回0,失败返回-1

第一个参数是存放的有名管道的路径,包含了有名管道文件的名字,例如:"/tmp/myfifo"的意思就是,在tmp目录下创建了一个名为myfifo的管道文件。但是,如果你写成"/mnt/hgfs/share/myfifo"就会失败,这个是共享目录,链接到windows所以会失败。

第二个参数是读写权限,是个八进制的数,这个以后会花时间写,本文的读写权限为0777(可读可写可执行)

创建成功的管道文件,就可以把他当做是普通文件一样进行操作(但是本质上两者不同)可操作如下:

open()

read()

write()

close()

3、实例 有不少的文章说管道文件只能以读写的方式打开,这个说法是正确的

1、假设有名管道文件以读或写的方式打开。我们知道管道文件是有出入口的(有名管道和普通文件一样共用一个出入口,只要一个文件标识符,无名管道有两个标识符,一个入口一个出口,分开的。)读写的方式打开,就代表,一个进程自己把东西写进管道,再读出来给自己用,这个意义就不大了,管道是用来给两个进程的通信,不是这样用的。网上的说法说“只能以读或写的方式打开“是对的

2、但是有些人在代码实现上面就出现了错误 点击打开链接

写操作

#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h> int main()
{const char *fifo_name = "/tmp/my_fifo";int pipe_fd = -1;int data_fd = -1;int res = 0;const int open_mode = O_WRONLY | O_NONBLOCK;int bytes_sent = 0;char buffer[PIPE_BUF + 1];int bytes_read = 0;if(access(fifo_name, F_OK) == -1){printf ("Create the fifo pipe.\n");res = mkfifo(fifo_name, 0777);if(res != 0){fprintf(stderr, "Could not create fifo %s\n", fifo_name);exit(EXIT_FAILURE);}}printf("Process %d opening FIFO O_WRONLY\n", getpid());pipe_fd = open(fifo_name, open_mode);printf("Process %d result %d\n", getpid(), pipe_fd);printf("%d\n",pipe_fd);if(pipe_fd != -1){bytes_read = 0;data_fd = open("Data.txt", O_RDONLY);if (data_fd == -1){close(pipe_fd);fprintf (stderr, "Open file[Data.txt] failed\n");return -1;}bytes_read = read(data_fd, buffer, PIPE_BUF);buffer[bytes_read] = '\0';while(bytes_read > 0){res = write(pipe_fd, buffer, bytes_read);if(res == -1){fprintf(stderr, "Write error on pipe\n");exit(EXIT_FAILURE);}bytes_sent += res;bytes_read = read(data_fd, buffer, PIPE_BUF);buffer[bytes_read] = '\0';}close(pipe_fd);close(data_fd);}elseexit(EXIT_FAILURE);printf("Process %d finished\n", getpid());exit(EXIT_SUCCESS);
}

pipe_fd 是定义的文件操作符,我们知道,open函数打开成功返回的是0,失败返回-1;上面返回-1说明文件打开失败

为什么会打开失败呢?因为程序没有阻塞在open()函数里面,程序一直执行到后面直接close文件了。有名管道文件关闭了就不存在内容了,所以返回失败。

说明:源代码没有该打印语句,个人加上去测试的,具体点击链接查看别人的源代码

怎么修改呢?如下:

 const int open_mode = O_WRONLY | O_NONBLOCK;

修改为

 const int open_mode = O_WRONLY

结果:

可以看见,程序暂停了,阻塞在open函数里面,这才算是成功打开的操作

读操作

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <string.h>int main()
{const char *fifo_name = "/tmp/my_fifo";int pipe_fd = -1;int data_fd = -1;int res = 0;int open_mode = O_RDONLY | O_NONBLOCK;char buffer[PIPE_BUF + 1];int bytes_read = 0;int bytes_write = 0;memset(buffer, '\0', sizeof(buffer));printf("Process %d opening FIFO O_RDONLY\n", getpid());pipe_fd = open(fifo_name, open_mode);data_fd = open("DataFormFIFO.txt", O_WRONLY|O_CREAT, 0644);if (data_fd == -1){fprintf(stderr, "Open file[DataFormFIFO.txt] failed\n");close(pipe_fd);return -1;}printf("Process %d result %d\n",getpid(), pipe_fd);if(pipe_fd != -1){do{res = read(pipe_fd, buffer, PIPE_BUF);bytes_write = write(data_fd, buffer, res);bytes_read += res;}while(res > 0);close(pipe_fd);close(data_fd);}elseexit(EXIT_FAILURE);printf("Process %d finished, %d bytes read\n", getpid(), bytes_read);exit(EXIT_SUCCESS);
}

读操作同样是这个问题,

int open_mode = O_RDONLY | O_NONBLOCK;

修改为:

int open_mode = O_RDONLY;

最后再开一个终端,运行读操作(注意不要把之前写操作的终端关闭),最后结过如下:

当然他的最后结果对不对不是我谈论的范围,我只是告诉读者正确打开方式

总结一下:

管道文件的特殊性,要求管道文件要在读写的时候,先阻塞在写操作的open函数,当有读操作进来的时候,通信链路建立,写操作开始往管道里写东西,写完成之后,在读操作会把东西读出来,最后两个进程都正常结束退出。注意当你读完一次之后再去读管道文件的时候,是会失败的,因为我前面说过,管道就像是水管,流出去之后就没有了,read完成里面就没东西了。

声明:本文在参考他人blog情况下原创,转载请说明。如有侵权联系删除。

参考文献

1、https://www.cnblogs.com/fangshenghui/p/4039805.html

2、https://blog.csdn.net/best_fiends_zxh/article/details/52923560

3、https://blog.csdn.net/xqhrs232/article/details/53636364

linux下的有名管道文件读写操作相关推荐

  1. linux下测试磁盘的读写IO速度-简易方法

    linux下测试磁盘的读写IO速度-简易方法 参考资料: https://blog.csdn.net/zqtsx/article/details/25487185 一:使用hdparm命令 这是一个是 ...

  2. Linux下Mysql数据库的基础操作

    Linux下Mysql数据库的基础操作 一.Mysql数据介绍 二.数据库相关术语介绍 1.数据库相关名词 2.相关术语介绍 三.Mysql数据库的管理 1.创建数据库用户 2.查询用户状态 3.修改 ...

  3. linux下查看系统socket读写缓冲区

    一:linux下查看系统socket读写缓冲区大小配置: http://blog.csdn.net/herecles/article/details/8146017 1. tcp 收发缓冲区默认值 [ ...

  4. linux下分区ntfs,简易教程:Linux下NTFS分区的写操作

    Linux下NTFS分区的写操作只需通过简单点击即可完成. 在你正常的工作中,假如你装的是双系统,其中一个是Winodws系统,而你又在Linux环境下办公,需要用到Windows分区中的某文档资料或 ...

  5. LINUX下用户和组的操作与相关的配置文件

    LINUX下用户和组的操作与相关的配置文件 与用户相关的配置文件 passwd文件 shadow文件 group文件 用户和组的操作 和用户相关的操作 useradd userdel usermod ...

  6. S3C2440 Linux下的I2C驱动以及I2C体系下对EEPROM进行读写操作。

    这篇文档算上期末复习这段时间其实拖了有好久了,因为从一开始接触linux的i2c驱动体系我就各种凌乱,因为起初脑海中既没有整体框架也不熟悉相关体系下的结构,所以四处乱看,经常性的在看内核代码时看着看着 ...

  7. 记一次Linux 下磁盘分配和扩容操作

    Linux 下磁盘操作命令 前言 磁盘分区.格式化分区.挂载目录 挂载目录扩容 对原有的磁盘的最后一个分区扩容 对原有的磁盘的剩余空间增加主分区 前言 企业真实场景由于硬盘常年大量读写,经常会出现坏盘 ...

  8. Linux学习笔记2-文件读写操作

    1.查看执行过的命令(历史文件) 执行过的命令,可以在终端按上下方向键来选择. 用History命令会列出历史命令(只保存最近使用的一千条命令,保存在家目录.bash_history文件)前面是标号, ...

  9. Linux下C编程-----IO/文件操作 模拟linux ls程序显示文件系统树形结构(2)

    Linux下的IO/文件操作练习,知识虽然简单 但是往往基础容易被忽略,偶尔的练习是有必要的. 练习printf /****************************************** ...

最新文章

  1. linux安装redis教程yum,linux下yum安装redis以及使用
  2. Spring越来越强,而我们越来越快餐!离开了Spring,居然API都写不出来了!
  3. 如何构建可视化的营销数据大屏?
  4. 优化MySQL数据类型——《深究MySQL》
  5. C#与U3D中字符串尾0
  6. 从零开始-小程序采坑记录
  7. 自定义SpringBoot start 自动打印日志
  8. 信息收集 ——情报分析
  9. 《C语言编程魔法书:基于C11标准》——1.3 主流C语言编译器介绍
  10. akka连接是什么_什么是Akka?
  11. Mysql_多表查询练习
  12. RHEL 7关闭防火墙及SElinux
  13. 最全的搜索引擎入口和分类目录入口
  14. 乘风破浪的技术大咖再次集结 | 腾讯云TVP持续航行中
  15. 全基因组基因家族成员相关数据获取
  16. ant 的详细的入门教程
  17. LaTeX(1)设置部分文本居中左对齐、居中右对齐
  18. 蓝桥杯--历届真题 最优包含【第十届】【决赛】【B组】
  19. 学术派 | 基于AI的视频精彩度分析技术
  20. ubuntu: /lib/modules/xx/build 目录不存在的解决办法(安装Linux headers失败)

热门文章

  1. 制作系统U盘详细教程,以及分盘等基础操作
  2. python实现Excel文件读取的程序(附源代码)
  3. 服务器柜机位置摆放电子图,客厅柜机摆放—客厅柜机空调摆放方法介绍
  4. 本地maven仓库有jar包但是pom却报错
  5. Java实现GTA5自动抽车,提高中奖概率
  6. 免越狱无视证书掉签,只需这几步简单解决,不再为记录发愁
  7. sublime text3 的PHP函数追踪定位插件ctags和codeBeautifier
  8. android 三星手机拍照旋转90度,解决三星调用系统相机拍照显示图片旋转90度横着的问题...
  9. 好程序员打造核心教培天团,着力培养IT高级研发人才
  10. 策略服务器未运行错误5,win7系统使用诊断检查网络提示“诊断策略服务未运行”的解决方法...