【Linux】进程间通信——管道

news2024/11/18 21:28:54

目录

一、概念

二、管道函数

1.popen函数

2.pclose函数

3.文件函数

三、管道的操作

1.管道的分类

无名管道

有名管道

管道的特点

四、管道的实现


操作系统对进程之间相互保护

两个进程之间相互通信

前言:

进程间通信的方法/IPC机制都有哪些:

  1. 管道
  2. 套接字
  3. 信号量
  4. 共享内存
  5. 消息队列

一、概念

什么是管道?

当从一个进程连接数据流到另一个进程时,使用“管道”。通常把一个进程的输出通过管道连接到另一个进程的输入

        shell命令的连接是通过管道字符来完成,如下所示:

cmd1|cmd2

        shell负责安排两个命令的标准输入和标准输出。cmd1的标准输入来自终端键盘,cmd1的标准输出传递给cmd2,作为它的标准输入。cmd2的标准输出来接到终端屏幕。管道是在内存上分配空间,cmd1把数据写到内存中,cmd2从内存中读取数据,效率高。

        shell做的工作实际就是对标准输入和标准输出流进行重新连接,使数据流从键盘输入通过两个命令最终输出到屏幕上。

图示为用管道将多个进程连接起来     

二、管道函数

1.popen函数

头文件:

#include<stdio.h>

函数原型:

FILE *popen(const char * command,const char * open_mode);
  • 作用:
    • 允许一个程序将另一个程序作为新程序来启动,并可以传递数据给它或者通过它接收数据。        
  • 参数:
    • 第一个参数command字符串是要运行的程序名和相应参数。open_mode必须是“r”或者是“w”。
    • 第二个参数open_mode必须是“r”或者是“w”。如果open_mode是“r”,被调用的程序输出就可以被调用程序使用,调用程序利用popen函数返回的FILE*文件流指针,就可以通过常用的stdio库函数(如fread)来读取被调用程序的输出。如果open_mode是“w”,调用程序就可以用fwrite调用向被调用程序发送数据,而被调用程序可以在自己的标准输入流上读取数据,然后做出相应的操作。
  • 返回值:
    • 失败返回空指针

2.pclose函数

头文件:#include<stdio.h>

函数原型:

FILE *pclose(FILE *stream_to_close);
  • 作用:
    • 关闭与之关联的文件流。        
  • 返回值:
    • 通常是它所关闭的文件流所在进程的退出码。

3.文件函数

#include<unistd.h>

write:

把缓冲区Buf的前nbytes个字节写入与文件描述符fildes关联的文件中。返回实际写入的字节数。

size_t write(int fildes,const void *buf,size_t nbytes)

read:

从文件描述符filedes相关联的文件里读入nbytes个字节的数据,并且把他们放到数据区buf中。返回实际读入的字节数。

size_t read(int dildes,void* buf,size_t nbytes);

open:

创建一个新的文件描述符

#include<unistd.h>
#include<fcntl.h>
#include<sys/stat.h>

int open(const char * path,int oflags);
int open(const char *path,int oflags,mode_t mode);

三、管道的操作

管道也是个文件,用文件操作的命令对管道进程操作。管道存放在内存中,读取速度很快。

1.管道的分类

  1. 有名管道:在任意两个进程间通信
  2. 无名管道:在父子进程间通信

无名管道

  • 只能进行父子间通信
  • 使用pipe创建无名管道
  • pipe:
    • 头文件:
    • #include<unistd.h>
      
      int pipe(int file_descriptor[2]);
    • 成功返回0,失败返回-1
    • file_descriptor[0]:管道读端的描述符
    • file_descriptor[1]:管道写端的描述符
    • 两个返回的文件描述符以一种特殊的方式连接起来。写到file_deacriptor[1]的所有数据都有可以从file_descriptor[0]读回来。数据基于先进先出的原则(通常写为FIFO)进行处理,这意味着如果把字节1,2,3写到file_deacriptor[1],从file_deacriptor[0]读取到的数据也会是1,2,3,这也栈的处理方式不同,栈采用后进先出,写作LIFO。

  • 函数在两个程序之间传递数据不需要启动一个shell来解释所请求的命令,他同时还提供了对亵读写数据的更多控制。
  • pipe函数的参数是一个由两个整数类型的文件描述符组成数组的指针。该函数在数组中天上两个新的文件描述符后返回0,如果失败则返回-1并设置error来表示失败的原因。
  • 代码演示:父进程写入数据,子进程读取:
  • #include<stdio.h>
    #include<unistd.h>
    #include<stdlib.h>
    #include<string.h>
    #include<assert.h>
    
    int main()
    {
    
        int fd[2];//写端描述符
    	assert(pipe(fd)!=-1);
    
    	pid_t pid=fork();//open->fork,父子共享文件描述法
        assert(pid!=-1);
    	if(pid==0)//子进程
    	{
    		close(fd[1]);
    		char buff[128]={0};
    		read(fd[0],buff,127);
    		printf(fd[0]);
    	}
    	else
    	{
    		close(fd[0]);
    		write(fd[1],"hello",5);
    		close(fd[1]);
    	}
    	exit(0);
    }
    
  • 代码牵扯到一个知识点:先open打开文件再fork出子进程,此时,父子进程共享文件偏移量/文件描述符。注意:这里使用的文件描述符而不是文件流,所以我们必须用底层的read和write调用来访问数据,而不是用文件流库函数fread和fwrite。
  • fork,可以把fds[0][1]带给子进程,传递描述符

    子进程可以共享,管道就通过fork把管道描述符带给fork

有名管道

  • 有名管道实现任意进程间通信
  • 有名管道的创建:
    • 创建命令:mkfifo
    • 打开管道:open();
    • 读数据:read();
    • 写入数据:write();
    • 关闭管道:close()
  • 代码实现有名管道间通信:

a.c:读取fifi的管道文件,写入5个字符的"hello"数据进去。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<fcntl.h>
#include<string.h>

int main()
{
	int fd=open("fifi",O_WRONLY);
	assert(fd!=-1);
	printf("fd=%d\n",fd);
	write(fd,"hello",5);
	close(fd);
}

b.c

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<fcntl.h>
#include<string.h>

int main()
{
	int fd=open("./fifi",O_RDONLY);
	assert(fd!=-1);
	printf("fd=%d\n",fd);
	char buff[128]={0};
	read(fd,buff,127);//不读\0
	printf("read %s\n",buff);
	close(fd);
}

管道的特点

  1. 管道必须读,写进程同时open会阻塞
  2. 如果管道中没有数据,那么read就会堵塞
  3. 管道的写端关闭,读read返回值为0,终止程序
  4. 管道的读端关闭,写端写入时产生信号,终止程序
  5. 管道打开的时候只有只读只写两种方式,不能是读写方式,因为读写方式是未定义的
  6. 管道是半双工的:
    1. 全双工、单工、半双工、
    2. 全双工:任意时刻都是双向的
    3. 半双工:某一时刻只能是一个方向
    4. 单:发送方和接收方只有一个方向
  7. 管道文件大小永远为0

四、管道的实现

open打开管道后,会开辟如下所示大小的空间:

头指针:当前待写入的数据位置

尾指针:当前待读取数据的位置,图示为即将读取h

abcdefg为已经读取的数据,用户使用过的空间可以被重新利用,当前空间满了可以写入在缓冲区指针位置。--相当于循环队列

IPC机制有:IPC进程间通信。

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

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

相关文章

求二进制中1的个数的三种方法

求二进制中的1的个数 文章目录第一种方法&#xff1a;模2除2第二种方法&#xff1a;利用操作符右移后与1第三种方法&#xff1a;该数与上比它小1的数&#xff08;最优的方法&#xff09;第一种方法&#xff1a;模2除2 首先明白如何得到一个数的十进制的每一位&#xff1f; 以1…

PHP代码审计入门-DVWA靶场CSRF篇

0x00 写在前面 从零学习php&#xff0c;最终目的实现代码审计入门&#xff0c;软件采用sublime text&#xff0c;环境使用phpstudy搭建&#xff0c;数据库是navicat&#xff0c;需要有基本的前端基础、简单的phpmysql后端基础、渗透知识和漏洞原理&#xff0c;文章跟随流沙前…

bizlog通用操作日志组件(使用篇)

引言 如上图所示&#xff0c;产品的新需求&#xff0c;需要将操作人在系统中具体编辑操作的变更内容记录下来。 按正常思路来说&#xff0c;无非就是将修改前后的对象字段逐个比较&#xff0c;再拼接为详细的操作描述记录到操作日志表中。如果是一个模块的需求&#xff0c;单独…

用HTML+CSS做一个学生抗疫感动专题网页设计作业网页

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

springboot如何修改thymeleaf中默认的页面路径及默认的后缀名呢?

转自: springboot如何修改thymeleaf中默认的页面路径及默认的后缀名呢? 下文讲述springboot修改thymefleaf修改页面默认路径及后缀名的方法分享&#xff0c;如下所示: 实现思路:只需在配置文件中修改相应的配置即可&#xff0c;如&#xff1a;application.yaml spring:thym…

MySQL单表查询操作详解,不做CRUD程序员

在我们对数据进行操作时&#xff0c;查询无疑是至关重要的&#xff0c;查询操作灵活多变&#xff0c;我们可以根据开发的需求&#xff0c;设计高效的查询操作&#xff0c;把数据库中存储的数据展示给用户。 文章目录前言1. 基础查询1.1 基础查询语法1.2 基础查询练习2. 条件查询…

大数据路线

一、概念部分 1.1 大数据、数仓、数据湖、中台的概念 区别数仓数据湖使用场景批处理&#xff0c;BI&#xff0c;数据可视化机器学习、预测分析、数据分析Schema写入型读取型数据源类型OLTP为主的结构化数据loT&#xff0c;日志&#xff0c;各个端等结构非结构均可性价比需要快…

牛客刷题总结——Python入门08:面向对象、正则表达式

&#x1f935;‍♂️ 个人主页: 北极的三哈 个人主页 &#x1f468;‍&#x1f4bb; 作者简介&#xff1a;Python领域优质创作者。 &#x1f4d2; 系列专栏&#xff1a;《牛客题库-Python篇》 &#x1f310;推荐《牛客网》——找工作神器|笔试题库|面试经验|实习经验内推&am…

Design A Youtube

title: Notes of System Design No.05 — Design a Youtube description: ‘Design a Youtube’ date: 2022-05-14 13:45:37 tags: 系统设计 categories: 系统设计 01. Funtional Requirements 02. Non Functional Requirements 03.Assumption 04 API 05 High Level Design 上…

05 MSYS2中安装树莓派32位和64位ARM交叉编译工具

作者将狼才鲸创建日期2022-11-14 Gitee源码和工程地址&#xff1a;才鲸嵌入式 / 开源安防摄像机&#xff08;嵌入式软件&#xff09;CSDN文章地址&#xff1a;项目介绍&#xff1a;开源安防摄像机&#xff08;嵌入式软件&#xff09; 4.3 MSYS2中安装32位和64位ARM交叉编译工具…

1524_AURIX TC275存储分布_下

全部学习汇总&#xff1a; GreyZhang/g_TC275: happy hacking for TC275! (github.com) 继续前面的学习&#xff0c;这一次把这个小章节的剩余信息看完。 这一部分是外设相关的寄存器地址区间描述&#xff0c;看起来一个模块的地址空间占用基本都是256个字节。具体包括什么暂时…

Unity技术手册-UGUI零基础详细教程-Graphic Raycaster 射线检测和Canvas Group

往期文章分享点击跳转>《导航贴》- Unity手册&#xff0c;系统实战学习点击跳转>《导航贴》- Android手册&#xff0c;重温移动开发 本文约3千字&#xff0c;新手阅读需要6分钟&#xff0c;复习需要2分钟 【收藏随时查阅不再迷路】 &#x1f449;关于作者 众所周知&#…

outsystems合集系列(三)

outsystemsModeling DataDatabase Entities的介绍如何创建Database Entities如何用excel快速导入真实数据到entity?如何用excel快速创建entity并导入真实数据?Static Entities的介绍Modeling Data 这一节我将介绍在outsystems中建模数据(model data)的一些思路。注意在这里我…

shellcode 中 null byte 的成因和避免方式总结

背景 shellcode 中要避免 null byte&#xff08;\x00&#xff09;这个是个通用的概念&#xff08;windows&#xff0c;linux 都是一样&#xff09;&#xff0c;因为栈溢出的数据作为字符串写入到栈上&#xff0c;\x00 会作为字符串终止符&#xff0c;毁掉整个 shellcode。 这…

HTML+CSS个人静态网页设计

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

【AGC】安全规则resource.data获取不到字段

问题背景 在表结构里有但resource.data获取不到uid字段 解决该问题 request变量是指请求&#xff0c;request.resource.data是请求数据的所有字段和值的映射&#xff1b;resource变量是指所请求的数据在数据库中保存的状态&#xff0c;resource.data是数据库中保存数据的所有…

教师工作量管理系统思路(链表应用)

教师工作量管理系统思路&#xff08;链表应用&#xff09; 文章目录教师工作量管理系统思路&#xff08;链表应用&#xff09;题目描述&#xff1a;初始信息菜单部分数据结构功能实现查询历史信息从键盘录入信息信息删除和修改工作量计算如何存储到工作量信息链表中&#xff1f…

Bootstrap响应式轮播效果网页(1+X Web前端开发中级 例题)

文章目录 &#x1f4c4;题目要求 &#x1f9e9;说明 &#x1f9e9;效果图 &#x1f4bb;HTML代码 &#x1f3af;实现效果 &#x1f4f0;完整答案 &#x1f4c4;题目要求 阅读下列说明、效果图和HTML代码&#xff0c;进行静态网页开发&#xff0c;填写&#xff08;1&…

springboot12总结篇(9 10 11)

1.视图解析 以重定向为例 如果返回字符串 则会调用视图解析器thymeleafResolver判断返回值为普通字符串&#xff0c;返回thymeleafView调用其render方法&#xff0c;拼接直接访问 2.异常处理 404 ControllerAdvie 处理异常类 ExceptionHandler ControllerAdvie 处理异常类…

适配器模式

思考适配器模式 适配器模式通过转换已有的接口&#xff0c;达成目标需要的接口 适配器模式还可以将多种差异化接口适配成同一接口做统一输出 1.适配器模式的本质 适配器模式的本质是:转换匹配,复用功能。 适配器通过转换调用已有的实现&#xff0c;从而能把已有的实现匹配成需要…