LinuxC编程——进程间通信(一)(管道)

目录

  • 一、Linux平台通信方式发展史
  • 二、进程间通信方式⭐⭐⭐
  • 三、无名管道
    • 3.1 特点⭐⭐⭐
    • 3.2 函数pipe
    • 3.3 注意事项⭐⭐⭐
    • 3.4 练习
  • 四、有名管道
    • 4.1 特点⭐⭐⭐
    • 4.2 函数 mkfifo
    • 4.3 注意事项⭐⭐
    • 4.4 练习
  • 五、无名管道与有名管道对比⭐⭐

复杂的编程环境通常使用多个相关的进程来执行有关操作。进程之间必须进行通信,来共享资源和信息。因此,要求内核提供必要的机制,这些机制通常称为进程间通信(InterProcess Communication, IPC)。

一、Linux平台通信方式发展史

  1. 早期通信方式:早期的Unix IPC包括管道、FIFO和信号
  2. AT&T的贝尔实验室,对Unix早期的进程间通信进行了改进和扩充,形成了“system V IPC”,其通信进程主要局限在单个计算机内。
  3. BSD(加州大学伯克利分校的伯克利软件发布中心),跳过了只能在同一计算机通信的限制,形成了基于套接字(socket)的进程间通信机制。

二、进程间通信方式⭐⭐⭐

  1. 早期通信:无名管道(pipe),有名管道(fifo)、信号(sem)
  2. system V IPC:共享内存(share memory) 、信号灯集(semaphore)、消息队列(message queue)
  3. BSD:套接字(socket)

三、无名管道

3.1 特点⭐⭐⭐

  1. 只能用于具有亲缘关系的进程间进行通信
  2. 半双工通信,具有固定的读端与写端
    (单工:只能单方面传输信息->广播
    半双工:可以双向,但是同一时间只能一个方向传输信息
    全双工:可以双向同时传输信息)
  3. 无名管道可以看作一种特殊的文件,对它的读写采用文件IO:read、write
  4. 管道是基于文件描述符通信方式。当一个无名管道创建会自动创建两个文件描述符,分别的fd[0]、fd[1],其中fd[0]固定的读端,fd[1]固定的写端

3.2 函数pipe

int pipe(int fd[2])

  • 功能:创建无名管道
  • 参数:文件描述符(fd[0]:读端 fd[1]:写端)
  • 返回值:成功 0;失败 -1
    注📢:管道要用文件I/O进行操作(read,write,close)且管道创建后,fd[0]=3,fd[1]=4
    例:
    在这里插入图片描述
    在这里插入图片描述

3.3 注意事项⭐⭐⭐

  1. 当管道中无数据时,读操作会阻塞;管道中无数据,将写端关闭,读操作会立即返回
  2. 管道中装满(管道大小64K)数据写阻塞,一旦有4k空间,写继续,直到写满为止
  3. 只有在管道的读端存在时,向管道中写入数据才有意义。否则,会导致管道破裂,向管道中写入数据的进程将收到内核传来的SIGPIPE信号 (通常Broken pipe错误)。(GDB调试可以查看到)

代码示例:

#include <stdio.h>
#include <unistd.h>
#include <string.h>int main(int argc, char const *argv[])
{int fd[2] = {0};if (pipe(fd) < 0){perror("pipe error");return -1;}printf("fd[0]:%d  fd[1]:%d\n", fd[0], fd[1]);char buf1[32] = {"hello world!"};char buf2[32] = {0};// write(fd[1],buf1,strlen(buf1)); //往管道写入buf1// ssize_t s = read(fd[0],buf2,32);  //从管道读取数据到buf2// printf("%s %d\n",buf2,s);// close(fd[0]);// close(fd[1]);
#if 0// 1.管道中无数据,读阻塞read(fd[0], buf2, 32);
#endif
#if 0// 2.将写端关闭,读操作会立即返回close(fd[1]);read(fd[0],buf2,32);
#endif
#if 1//3.1 当无名管道中写满数据64k,写阻塞char buf[65536] = {0};write(fd[1], buf, 65536);printf("full\n");write(fd[1], "a", 1);printf("write a ok\n");//至少读出4k的空间,才能继续写read(fd[0], buf, 4095);write(fd[1], 'a', 1);printf("write 'a' ok\n");
#endif
#if 1// 3.1 将读端关闭,继续写close(fd[0]);write(fd[1], "a", 1);printf("ok...\n");
#endif// close(fd[0]);// close(fd[1]);return 0;
}

第三种情况管道破裂,通过GDB调试查看到的结果如下:
在这里插入图片描述

3.4 练习

父子进程实现通信,父进程循环从终端输入数据,子进程循环打印数据,输入一次打印一次,当输入quit结束,使用无名管道

/*练习:父子进程实现通信,父进程循环从终端输入数据,子进程循环打印数据,当输入quit结束,使用无名管道
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>int main(int argc, char const *argv[])
{char buf[32] = {0};int fd[2] = {0};if(pipe(fd)<0) //创建无名管道{perror("pipe err");return -1;}pid_t pid = fork();if(pid < 0){perror("fork err");return -1;}else if(pid == 0){while (1) //子进程循环从管道读取数据,管道为空阻塞{read(fd[0],buf,32);if(strcmp(buf,"quit")==0)exit(0);printf("%s\n",buf);}  }else{while(1)//循环从终端输入数据,循环往管道写入数据{//scanf("%s",buf);fgets(buf,32,stdin);if(buf[strlen(buf)-1] == '\n')buf[strlen(buf)-1] = '\0';write(fd[1],buf,strlen(buf)+1);if(strcmp(buf,"quit")==0)exit(0);}wait(NULL);}close(fd[0]);close(fd[1]);return 0;
}

四、有名管道

4.1 特点⭐⭐⭐

  1. 可以用于两个不相关的进程之间通信
  2. 有名管道可以通过路径名指出,在文件系统中可见,但内容存放在内存里
  3. 通过文件IO操作
  4. 遵循先进先出,故不支持lseek操作
  5. 半双工通信

4.2 函数 mkfifo

int mkfifo(const char *filename,mode_t mode);

  • 功能:创健有名管道
  • 参数:
    • filename:有名管道文件名
    • mode:权限
  • 返回值:成功:0;失败:-1,并设置errno号
    注意对错误的处理方式:📢📢
    如果错误是file exist时,注意加判断,如:if(errno == EEXIST)
    执行如下代码:
    在这里插入图片描述
    第一次运行:
    在这里插入图片描述
    再次运行:
    在这里插入图片描述
    处理方式:捕捉错误码,进行过滤即可👇
    在这里插入图片描述
  1. 由上面的有名管道特点的第二条可以知道,写入有名管道的内容并非存放在文件中,而是存在内存,也就是说有名管道文件的大小为0,下面进行验证:
    在这里插入图片描述
    在写后面加一个while死循环,运行后会等写完阻塞,不读出数据。然后在终端可以查看当前管道文件的大小,结果是大小为0👇
    在这里插入图片描述

4.3 注意事项⭐⭐

  1. 只写方式,写阻塞,直到另一个进程将读打开
  2. 只读方式,读阻塞,直到另一个进程将写打开
  3. 可读可写,管道中无数据,读阻塞。

验证1,2:
创建两个c文件,一个以只读方式打开有名管道,从中读数据;另一个以只写方式打开同一个有名管道,从中写数据。
只读
在这里插入图片描述
只写
在这里插入图片描述
通过运行可以看到,运行了其中任意一个,会发生阻塞,只有当再运行另一个才可以解除阻塞,两个程序得以顺利执行下去。验证了只写方式,写阻塞,直到另一个进程将读打开只读方式,读阻塞,直到另一个进程将写打开。
还可以得知,上面程序并不是在read或iwrite发生阻塞,而是在open函数处发生了阻塞

补充:如果所有写进程都关闭命名管道,则只读进程的读操作会认为到达文件末尾,读操作解除阻塞并返回
验证:
以只读方式打开有名管道的程序代码1.c👇
在这里插入图片描述
以只写方式打开有名管道程序代码2.c👇
在这里插入图片描述
先执行1.c,会发生阻塞;再执行2.c,2.c不会往管道写入数据(保证1.c不会因为管道中有数据而解除阻塞),2.c间隔1秒关闭管道,可以看到原先阻塞的1.c也会在2.c执行1秒后解除阻塞,且read返回值为0。

4.4 练习

通过有名管道实现cp文件复制
方法一:两个c文件,一个只读管道,一个只写管道
3cp_MkfifoToDest.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{if(argc != 2){printf("Please input %s <des>\n",argv[0]);return -1;}if(mkfifo("./fifo",0666) < 0)//创建有名管道{//处理文件已存在的情况if(errno == EEXIST)//EEXTST=17{printf("file eexist\n");}else{perror("mkfifo err");return -1;}}//打开管道和目标文件int fd = open("./fifo",O_RDONLY);//此处一定不要用可读可写的方式打开//若以可读可写的方式打开,管道中无数据则读阻塞if(fd<0){perror("open fifo err");return -1;}int dest = open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,0666);if(fd<0){perror("open dest err");return -1;}//循环读管道,写目标文件ssize_t s;char buf[32] = {0};while ((s=read(fd,buf,32)) != 0)write(dest,buf,s);close(fd);close(dest);return 0;
}

3cp_SrcToMkfifo.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{if(argc != 2){printf("Please input %s <src>\n",argv[0]);return -1;}if(mkfifo("./fifo",0666) < 0)//创建有名管道{//处理文件已存在的情况if(errno == EEXIST)//EEXTST=17{printf("file eexist\n");}else{perror("mkfifo err");return -1;}}//打开管道和源文件int fd = open("./fifo",O_WRONLY);if(fd<0){perror("open fifo err");return -1;}int src = open(argv[1],O_RDONLY);if(fd<0){perror("open src err");return -1;}ssize_t s;char buf[32] = {0};while ((s=read(src,buf,32)) != 0){write(fd,buf,s);}close(fd);close(src);return 0;
}

运行结果:
在这里插入图片描述

方法二:单个c文件,用父子进程实现,父进程只写有名管道,子进程只读有名管道

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>int main(int argc, char const *argv[])
{if (argc != 3){printf("Please iniput %s <src> <dest>\n", argv[0]);return -1;}if (mkfifo("./fifo", 0666) < 0) //创建有名管道{//处理文件已存在的情况if (errno == EEXIST) //EEXTST=17{printf("file eexist\n");}else{perror("mkfifo err");return -1;}}//打开管道、源文件、目标文件int src = open(argv[1], O_RDONLY);if (src < 0){perror("open src err");return -1;}int dest = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);if (dest < 0){perror("open dest err");return -1;}ssize_t s;char buf[32] = {0};pid_t pid = fork(); // 创建子进程if (pid < 0){perror("fork err");return -1;}else if (pid == 0) //子进程从有名管道中读出数据,写到目标文件中{int fd = open("./fifo", O_RDONLY); //管道设置为只读if (fd < 0){perror("open fifo err");return -1;}while ((s = read(fd, buf, 32)) != 0)write(dest, buf, s);printf("child end...\n");close(fd);exit(0);}else //父进程从源文件读出数据,写到有名管道中{int fd = open("./fifo", O_WRONLY); //管道设置为只写if (fd < 0){perror("open fifo err");return -1;}while ((s = read(src, buf, 32)) != 0)write(fd, buf, s);printf("parent end...\n");close(fd);wait(NULL);}close(src);close(dest);return 0;
}

注:该程序容易被怀疑最后在子进程的read(fd, buf, 32)会发生阻塞,其实不然,这里用到了上面的一个要点:如果所有写进程都关闭命名管道,则只读进程的读操作会认为到达文件末尾,读操作解除阻塞并返回

五、无名管道与有名管道对比⭐⭐

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/33901.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CTF-Flask-Jinja2(持续更新)

放心&#xff0c;我会一直陪着你 一.知识一.在终端的一些指令1.虚拟环境2.docker容器二.SSTI相关知识介绍1.魔术方法2.python如何执行cmd命令3.SSTI常用注入模块(1)文件读取(2)内建函数eval执行命令(3)os模块执行命令(4)importlib类执行命令(5)linecache函数执行命令(6)subproc…

线性代数(二) 矩阵及其运算

前言 行列式det(A) 其实表示的只是一个值 ∣ a b c d ∣ a d − b c \begin{vmatrix} a & b\\ c & d\end{vmatrix} ad -bc ​ac​bd​ ​ad−bc&#xff0c;其基本变化是基于这个值是不变。而矩阵表示的是一个数表。 定义 矩阵与线性变换的关系 即得 ( a 11 a 12…

逆向破解学习-登山赛车

试玩 课程中的内容 Hook代码 import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.callbacks.XC_LoadPackage;public class HookComYoDo1SkiSafari2TXYYB_01 extends HookImpl{Overridepublic String p…

科技云报道:一波未平一波又起?AI大模型再出邪恶攻击工具

AI大模型的快速向前奔跑&#xff0c;让我们见识到了AI的无限可能&#xff0c;但也展示了AI在虚假信息、深度伪造和网络攻击方面的潜在威胁。 据安全分析平台Netenrich报道&#xff0c;近日&#xff0c;一款名为FraudGPT的AI工具近期在暗网上流通&#xff0c;并被犯罪分子用于编…

tensotflow中tf.title()和tf.broadcast()

tf.tile() 和 tf.broadcast_to() 都是 TensorFlow 中用于张量复制的函数&#xff0c;但它们的实现方式和使用场景略有不同。 tf.tile() 函数的定义如下&#xff1a; tf.tile(input, multiples, nameNone) 其中&#xff0c;input 表示要复制的张量&#xff0c;multiples 表示…

Vue输入框或者选择框无效,或者有延迟

问题剖析 使用Vue这种成熟好用的框架&#xff0c;一般出现奇奇怪怪的问题都是因为操作不当导致的&#xff0c;例如没有合理调用组件、组件位置不正确、没有合理定义组件或者变量、样式使用不当等等... 解决方案 如果你也出现了输入框输入东西&#xff0c;但是没有效果…

java8 求和

1.BigDecimal求和 对象字段求和 List<Car> listnew ArrayList<>(); BigDecimal sumOfBigDecimals list.stream().filter(Objects::nonNull).filter(c -> c.getMiles() ! null).map(Car::getMiles).reduce(BigDecimal.ZERO, BigDecimal::add);BigDecimal集合求…

(一)ES6 介绍

为什么学习ES6 ES6的版本变动内容最多&#xff0c;具有里程碑意义ES加入许多新的语法特性&#xff0c;编程实现更简单、搞笑ES6是前端发展趋势&#xff0c;就业必备技能 什么是ECMA ECMA&#xff08;European Computer Manufacturers Association&#xff09;&#xff0c;中…

如何使用异步IO编写高效的网络应用

如何使用异步IO编写高效的网络应用 在现代的网络应用中&#xff0c;处理大量的并发请求是必不可少的。传统的同步IO模式往往在面对高并发时效率低下。而异步IO则可以有效地提高网络应用的处理能力和性能。 异步IO是一种非阻塞的IO模型&#xff0c;它允许应用程序同时处理多个…

实时通信应用的开发:Vue.js、Spring Boot 和 WebSocket 整合实践

目录 1. 什么是webSocket 2. webSocket可以用来做什么? 3. webSocket协议 4. 服务器端 5. 客户端 6. 测试通讯 1. 什么是webSocket WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单&#xff0c;允许服务…

百度网盘非会员倍速播放(电脑端)

百度网盘非会员倍速播放&#xff08;电脑端&#xff09; 1. 打开edge浏览器&#xff0c;点击右上角的三个点后&#xff0c;选择“扩展” 2. 选择“管理扩展” 3. 选择“获取MicrosoftEdge扩展” 4. 搜索“Global Speed” 5. 选择Global Speed:视频速度控制&#xff0c;然…

PHP 求解两字符串所有公共子序列及最长公共子序列 支持多字节字符串

/*** 获取两字符串所有公共子序列【不连续的】 例&#xff1a;abc ac > ac** param string $str1 字符串1* param string $str2 字符串2** return array*/ function public_sequence(string $str1, string $str2): array {$data [[-1, -1, , 0, ]]; // 子序列容器【横坐标 …

配置Arduino+ESP32走过的巨坑

项目场景&#xff1a; 前几天去淘宝买了块ESP32拿来用&#xff0c;配置Arduino最新版ESP32 2.0.11走过的巨坑。 问题描述 先安装好了ArduinoIDE最新版&#xff08;教程里介绍去官网下&#xff09;&#xff0c;然后配置ESP32开发板&#xff0c;后面发现安装速度惊人。 去找加速…

Pytorch深度学习-----完整神经网络模型训练套路

系列文章目录 PyTorch深度学习——Anaconda和PyTorch安装 Pytorch深度学习-----数据模块Dataset类 Pytorch深度学习------TensorBoard的使用 Pytorch深度学习------Torchvision中Transforms的使用&#xff08;ToTensor&#xff0c;Normalize&#xff0c;Resize &#xff0c;Co…

git 使用步骤

1、创建分支 git checkout -b cate 2、本地提交 将 cate 分支进行本地提交 git add . git commit -m "完成cate页面的开发" 3、远程推送 将本地的 cate 分支推送到码云 git push -u origin cate 4、合并本地分支 将本地 cate 分支中的代码合并到 master 主分支&am…

websocket知识点

http协议 http协议特点&#xff1a; 无状态协议每个请求是独立的单双工通信&#xff0c;且服务器无法主动给客户端发信息http协议受浏览器同源策略影响 http实现双向通信方法: 轮询长轮询iframe流sse EventSource websocket协议 websocket协议: 全双工协议支持跨域支持多…

自动测试框架airtest应用一:将XX读书书籍保存为PDF

一、Airtest的简介 Airtest是网易出品的一款基于图像识别和poco控件识别的一款UI自动化测试工具。Airtest的框架是网易团队自己开发的一个图像识别框架&#xff0c;这个框架的祖宗就是一种新颖的图形脚本语言Sikuli。Sikuli这个框架的原理是这样的&#xff0c;计算机用户不需要…

asp.net core webapi如何执行周期性任务

使用Api执行周期性任务 第一种&#xff0c;无图形化界面1.新建类&#xff0c;继承IJob&#xff0c;在实现的方法种书写需要周期性执行的事件。2.编写方法类&#xff0c;定义事件执行方式3.在启动方法中&#xff0c;进行设置&#xff0c;.net 6中在program.cs的Main方法中&#…

数据库--MySQL增删改查

数据库相关链接&#xff1a; 数据库--数据类型&#xff1a;http://t.csdn.cn/RtqMD 数据库--三大范式、多表查询、函数sql&#xff1a;http://t.csdn.cn/udJSG 基础的数据操作 在创建了数据库和数据库表之后&#xff0c;我们就可以在表中进行数据操作了。基础操作分为 添加 …

旅卦-火山旅

前言&#xff1a;人生就像一趟旅行&#xff0c;为谋生奔波也是旅&#xff0c;旅是人生的常态&#xff0c;我们看一下易经里的旅卦&#xff0c;分析下卦辞和爻辞以及自己的理解。 目录 卦辞 爻辞 总结 卦辞 旅&#xff1a;小亨&#xff0c;旅贞吉。 卦序&#xff1a;穷大者…