四十六、进程间通信——管道的分类与读写

46.1 管道介绍

46.1.1 管道通信

  • 管道是针对于本地计算机的两个进程之间的通信而设计的通信方法,建立管道后,实际获得两个文件描述符:一个用于读取而另一个用于写入
  • 最常见的 IPC 机制,通过 pipe 系统调用
  • 管道是单工的,数据只能向一个方向流动,需要双向通信时,需要建立起两个管道
  • 数据的读出和写入:
    • 一个进程向管道中写的内容被管道另一端的进程读出。
    • 写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据
  • 管道实际上就是建立在内核区域的一块缓存

46.1.2 管道分类

  • 匿名管道:

    • 在关系进程中进行(父进程和子进程、兄弟进程之间)
    • 由 pipe 系统调用,管道由父进程建立
    • 管道位于内核空间,其实是一块缓存
  • 命名管道(FIFO)
    • 两个没有任何关系的进程之间通信可通过命名管道进行数据传输,本质是内核中的一块缓存,另在文件系统中以一个特殊的设备文件(管道文件)存在
    • 通过系统调用 mkfifo 创建

46.1.3 管道创建

1 #include <unistd.h>
2 int pipe(int fd[2]);
  • 函数参数:两个文件描述符数组

    • fd[0]:为 pipe 的读端
    • fd[1]:为 pipe 的写端
    • fd[0] 用于读取管道,fd[1] 用于写入管道
  • 返回值:成功返回 0;出错返回 -1

  

  案例

  

46.1.4 管道读写

  • 管道主要用于不同进程间通信。实际上,通常先创建一个管道,再通过 fork 函数创建一个子进程

  

46.2 例子

46.2.1 管道应用

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <unistd.h>
 5 #include <sys/types.h>
 6 #include <sys/wait.h>
 7
 8 /**
 9  *  父进程通过管道传输两个数据给子进程
10  *  由子进程负责从管道中读取并输出
11  */
12 int main(void)
13 {
14     int fd[2];
15
16     /** 创建管道 */
17     if(pipe(fd) < 0){
18         perror("pipe error");
19         exit(1);
20     }
21
22     pid_t pid;
23     if((pid = fork()) < 0){
24         perror("fork error");
25         exit(1);
26     }
27     else if(pid > 0) { ///< 父进程
28         close(fd[0]);    ///< 父进程用来写入数据
29         int start = 1, end = 100;
30         if((write(fd[1], &start, sizeof(int))) != sizeof(int)) {
31             perror("write error");
32             exit(1);
33         }
34
35         if((write(fd[1], &end, sizeof(int))) != sizeof(int)) {
36             perror("write error");
37             exit(1);
38         }
39
40         close(fd[1]);
41         wait(0);
42     }
43     else {  ///< 子进程
44         close(fd[1]);   ///< 子进程用来读取数据
45         int start, end;
46         if(read(fd[0], &start, sizeof(int)) < 0){
47             perror("read error");
48             exit(1);
49         }
50
51         if(read(fd[0], &end, sizeof(int)) < 0){
52             perror("read error");
53             exit(1);
54         }
55
56         close(fd[0]);
57         printf("child process read start: %d, end %d\n", start, end);
58     }
59
60     return 0;
61 }

  编译运行:

  

46.2.2 在管道系统中使用 excu 函数

  

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <stdlib.h>
 4 #include <sys/wait.h>
 5 #include <sys/types.h>
 6
 7 char *cmd1[3] = {"/bin/cat", "/etc/passwd", NULL};
 8 char *cmd2[3] = {"/bin/grep", "root", NULL};
 9
10 int main(void)
11 {
12     int fd[2];
13     if(pipe(fd) < 0){
14         perror("pipe error");
15         exit(1);
16     }
17
18     int i = 0;
19     pid_t pid;
20     for(; i < 2; i++){
21         pid = fork();
22         if(pid < 0){
23             perror("fork error");
24             exit(1);
25         }
26         else if(pid == 0){
27             if(i == 0){ /** 第一个子进程负责往管道写入数据 */
28                 /** 关闭读端 */
29                 close(fd[0]);
30
31                 /** 将标准输出重定向到管道的写端
32                  * 下面命令的执行的结果会写入到管道中,而不是输出到屏幕 */
33                 if(dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO)
34                 {
35                     perror("dup2 error");
36                 }
37
38                 close(fd[1]);
39
40                 /** 调用 exec 函数执行 cat 命令 */
41                 if(execvp(cmd1[0], cmd1) < 0){
42                     perror("execvp error");
43                     exit(1);
44                 }
45                 break;
46             }
47
48             if(i == 1){/** 第二个子进程负责从管道读取数据 */
49                 /** 关闭写端 */
50                 close(fd[1]);
51
52                 /** 将标准输入重定向到管道的读端 */
53                 if(dup2(fd[0], STDIN_FILENO) != STDIN_FILENO){
54                     perror("dup2 error");
55                 }
56
57                 close(fd[0]);
58
59                 /** 调用 exec 函数执行 grep 命令 */
60                 if(execvp(cmd2[0], cmd2) < 0){
61                     perror("execvp error");
62                     exit(1);
63                 }
64
65                 break;
66             }
67         }
68         else {
69             if(i == 1){
70                 /** 父进程要等到子进程全部创建完毕才去回收 */
71                 close(fd[0]);
72                 close(fd[1]);
73                 wait(0);
74                 wait(0);
75             }
76
77         }
78     }
79     return 0;
80 }

  执行结果如下:

  

原文地址:https://www.cnblogs.com/kele-dad/p/10279756.html

时间: 2024-08-11 11:41:17

四十六、进程间通信——管道的分类与读写的相关文章

NeHe OpenGL教程 第四十六课:全屏反走样

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第四十六课:全屏反走样 全屏反走样 当今显卡的强大功能,你几乎什么都不用做,只需要在创建窗口的时候该一个数据.看看吧,驱动程序为你做完了一切. 在图形的绘制中,直线的走样是非常影响美观的,我们可以使用反走样解决这个问题.在众多的解决

四十六、android中的Bitmap

四十六.android中的Bitmap: http://www.cnblogs.com/linjiqin/archive/2011/12/28/2304940.html 四十七.实现调用Android手机的拍照功能: http://www.cnblogs.com/linjiqin/archive/2011/12/28/2304970.html

ActionScript3游戏中的图像编程(连载四十六)

总目录:http://blog.csdn.net/iloveas2014/article/details/38304477 3.1.2 以小见大--从细节损失洞悉滤镜本质 把它再改回内斜角,边缘似乎光滑了些,但这种错觉仅仅是由于阴影与蓝色的对比度不够强烈,才会让边缘的粗糙不够显眼.把文字颜色调成浅紫以后,转角处的锯齿依旧一览无余.(图 3.6),而Photoshop应用同样的设置则不会出现同样的问题(图 3.7). 图 3.6 模糊值为3的内侧斜角滤镜 图 3.7 大小等于3的斜面样式 如果认为

QT开发(四十六)——QT数据库编程基础

QT开发(四十六)--QT数据库编程基础 一.Qt SQL模块简介 1.Qt SQL模块简介 QT通过Qt SQL模块提供了对SQL数据库的支持,Qt SQL模块中的API分为三层:驱动层.SQL接口层.用户接口层. 如果要使用Qt SQL模块中的类,需要在工程文件(.pro文件)中添加QT += sql代码. 2.驱动层 驱动层为具体的数据库和SQL接口层之间提供了底层的桥梁,主要类包括Qt SQL模块中的QSqlDriver.QSqlDriverCreator.QSqlDriverCreat

【Unity 3D】学习笔记四十六:输入与控制——键盘事件

在游戏中,玩家控制主角移动,按键攻击,选择行走.都需要在程序中监听玩家的输入.unity为开发者提供了input库,来支持键盘事件,鼠标事件以及触摸事件.本文主要回顾键盘事件,以后会逐文复习鼠标以及触摸事件. 键盘事件 一般的PC键盘有104个不同的按键,在程序中通过监听这些按键事件,从而进一步执行逻辑操作.如:射击游戏中,W表示前进,S表示后退,A表示左移,D表示右移. 按下事件 在脚本中,用input.GetKeyDown( )方法将按键值作为参数,监听此按键是否被按下.按下返回true,否

程序员的奋斗史(四十六)——大学断代史(十)——给学弟学妹们的忠告——终结篇

文/温国兵 「写在前面」 大学断代史终于要完结了,就像一条再长的路总有终点一样.该系列文章前前后后写了一两个月,也该收尾了,至于收尾的文章,想了想,决定写写自己对学弟学妹的忠告.本篇文章以话题的形式呈现. 「关于专业」 我相信大多数的读者在高考填志愿都不知道软件工程或者计算机专业是做啥的,稀里糊涂就踏上了这条IT不归路.身处小乡村,消息相对闭塞,能使用电脑都是奢侈的事情,这就是当初我高考后的境况,相信现在有很大的改变.如果你对IT行业抱有一番热情,恭喜你,选对了好专业,好好学,今后的路错不了.如

“全栈2019”Java多线程第四十六章:判断任意线程是否已持有写锁

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多线程第四十六章:判断任意线程是否已持有写锁 下一章 "全栈2019"Java多线程第四十七章:判断锁是否为公平锁isFair() 学习小组 加入同步学习小组,共同交流与进步. 方式一:加入编程圈子. 方式二:关注头条号Gorhaf,私信"Java学习小组". 方式三:关

第四十六章

第四十六章1 马应该种田,不应该打仗:你应该工作,不应该总想买买买 天下有道,却走马以粪.天下无道,戎马生于郊. 天下有道的时候,马都在田里耕地,天下无道的时候,马都在战场打仗. 要放低欲望,把资源用在正地方. 各位朋友大家好,清晨起来,我们接着来讲<道德经>,看看老子老先生带给我们什么样人生启发.我在今天起床之前做梦,梦是让人黯然神伤的,我做梦梦见自己给一帮孩子妈妈,带着小朋友讲课,就讲这个“道”,结果妈妈不听,在下面聊天,孩子哭闹,乱作一团,大家说讲点感冒吧,讲“道”有什么用,我说“道”很

第四十六个知识点 在Sigma协议中,正确性,公正性和零知识性意味着什么

第四十六个知识点 在Sigma协议中,正确性,公正性和零知识性意味着什么 Sigma协议 Sigma协议是Alice想要向Bob证明一些东西的协议(Alice知道一些秘密).他们有下面的一般范式:Alice知道一个秘密,Alice和Bob都分享了一些相同的信息.因此: Alice给Bob发送了一个值,这个值叫做承诺(commitment). Bob均匀的随机选择一个挑战(challenge)发送给Alice. Alice计算一个回应(response)发送给Bob. Bob检查回应,接受或者拒绝