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;并被犯罪分子用于编…

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

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

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方法中&#…

旅卦-火山旅

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

java获取到heapdump文件后,如何快速分析?

简介 在之前的OOM问题复盘之后&#xff0c;本周&#xff0c;又一Java服务出现了内存问题&#xff0c;这次问题不严重&#xff0c;只会触发堆内存占用高报警&#xff0c;没有触发OOM&#xff0c;但好在之前的复盘中总结了dump脚本&#xff0c;会在堆占用高时自动执行jstack与jm…

560. 和为 K 的子数组

思路 本题的主要思路为创建一个哈希表记录每个0~i的和&#xff0c;在遍历这个数组的时候查询有没有sum-k的值在哈希表中&#xff0c;如果有&#xff0c;说明有个位置到当前位置的和为k。   有可能不止一个&#xff0c;哈希表负责记录有几个sum-k&#xff0c;将和记录下来。这…

【ArcGIS Pro二次开发】(60):按图层导出布局

在使用布局导图时&#xff0c;会遇到如下问题&#xff1a; 为了切换图层和导图方便&#xff0c;一般情况下&#xff0c;会把相关图层做成图层组。 在导图的时候&#xff0c;如果想要按照图层组进行分开导图&#xff0c;如上图&#xff0c;想导出【现状图、规划图、管控边界】3…

UNIX网络编程——TCP协议API 基础demo服务器代码

目录 一.TCP客户端API 1.创建套接字 2.connect连接服务器​编辑 3.send发送信息 4.recv接受信息 5.close 二.TCP服务器API 1.socket创建tcp套接字(监听套接字) 2.bind给服务器套接字绑定port,ip地址信息 3.listen监听并创建连接队列 4.accept提取客户端的连接 5.send,r…

包管理工具详解npm 、 yarn 、 cnpm 、 npx 、 pnpm(2023)

1、包管理工具npm &#xff08;1&#xff09;包管理工具npm&#xff1a; Node Package Manager&#xff0c;也就是Node包管理器&#xff1b;但是目前已经不仅仅是Node包管理器了&#xff0c;在前端项目中我们也在使用它来管理依赖的包&#xff1b;比如vue、vue-router、vuex、…

【Spring中MySQL连接错误】Cannot load driver class: com.mysql.cj.jdbc.Driver

Caused by: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method ‘dataSource’ threw exception; nested exception is java.lang.IllegalStateException: Cannot load driver class: com.mysql.cj.jdbc.Driver Caused by: java.lang.IllegalState…