【Linux】进程间通信之匿名管道

一、基本概念

我们了解到,进程之间是独立运行的,但有时需要在不同进程间传输数据以实现数据共享,有时多个进程需要共同使用同一资源,有时一个进程需要向其他进程发送消息以实现通知,有时一个进程需要完全控制另一个进程的执行以实现进程控制。

由于进程间的独立性,进程通信的成本较高。

进程间通信的核心是让不同进程能够访问同一资源,这资源必须由操作系统提供的第三方空间提供,而非某个进程的私有空间,以保持进程的独立性。访问这些第三方空间实际上就是在访问操作系统。

通常,操作系统会设立一个独立的通信模块,属于文件系统的一部分。它遵循两个标准:system V和POSIX。其中,system V用于本机内部进程通信,包括消息队列、共享内存和信号量;POSIX用于网络进程通信,包括消息队列、共享内存、信号量、互斥量、条件变量和读写锁。

在没有system V和POSIX标准之前,进程间通信主要通过管道实现,这种通信方式基于文件。

二、管道

1、回顾与深入

在学习命令行时,我们已经接触过管道。本质上,管道就像一个管子,两端有两种处理方式:在进入管道前对数据进行一次处理,管道中的数据是经过处理后的内容,然后在离开管道后再处理一次,得到的结果是经过前后两次处理的数据。

当时的学习仅停留在表面,实际上管道起到的是传递数据流的作用,连接两个进程,进程A通过管道将信息传递给进程B,管道本身不处理数据,只是传递数据。

2、实现方式

管道是一种基于文件的通信方式。我们回顾文件管理的相关内容:

【Linux】进程间通信之匿名管道

在进程的PCB中有一个struct files_struct指针,指向files_struct结构体,其中包含一个文件描述符指针数组,指向对应的struct file对象。每个struct file包含inode描述文件属性,file_operators定义操作文件的函数接口,文件缓冲区用于缓冲文件。如果管道文件存储在硬盘上,IO速度会非常慢,不利于进程间的快速通信。那么,在哪里既能快速存放文件又适合呢?答案是内存。

【Linux】进程间通信之匿名管道

我们去掉写入或读取硬盘的IO操作,将管道文件存放在缓冲区,其他进程通过文件描述符读取缓冲区内容,就可以实现进程间的管道通信。这种管道文件称为匿名管道。

解决了管道文件的存储问题后,接下来要解决的是其他进程如何通过文件描述符读取缓冲区内容。

我们知道,子进程由父进程创建,如果不做修改,相当于浅拷贝,父进程的PCB被复制,files_struct也被复制,它们指向相同的struct file。如果父进程以读方式打开管道文件(fd==3),以写方式打开管道文件(fd==4),子进程也会这样。然后父进程close(3),子进程close(4),实现父写子读;父进程close(4),子进程close(3),实现父读子写。

由于一个文件无法同时进行读写操作,所以匿名管道是一种半双工通信方式,即单向通信。当然,我们可以通过建立多个匿名管道来实现双向通信。

管道通信常用于父子进程通信,也可用于有“血缘”关系的兄弟进程、爷孙进程等进行通信。

3、匿名管道代码

代码语言:javascript代码运行次数:0

运行复制“`javascript#include int pipe(int pipefd[2]);//pipefd:文件描述符数组,其中pipefd[0]表示读端,pipefd[1]表示写端,值为对应的文件描述符//返回值:成功返回0,失败返回错误代码“`

pipe函数中,int fd[2]是一个输出型参数。

我们来实现一个父读子写的管道通信示例:

代码语言:javascript代码运行次数:0

运行复制“`javascript#include #include #include #include #include #include #include #include #define N 2#define NUM 1024using namespace std;void Writer(int wfd){ //定义要发送的字符串 string s = “this is your child”; //获取当前进程的pid pid_t myid = getpid(); int number = 0; char buffer[NUM]; while(1) { //此处相当于buffer[0] = ”;意思是将整个数组当做字符串用并且清空字符串 buffer[0] = 0; //将字符串、pid、以及计数器number按照”%s-%d-%d”格式写到buffer当中 snprintf(buffer,sizeof(buffer),”%s-%d-%d”,s.c_str(),myid,number++); //这里传过来的wfd为对应的文件描述符,然后将buffer中的有效内容写到管道文件缓冲区中 write(wfd,buffer,strlen(buffer)); sleep(5); }}void Reader(int rfd){ char buffer[NUM]; while(1) { //同上 buffer[0] = 0; //将文件描述符rfd读取的内容存储到buffer中,并返回读取到的字符个数n ssize_t n = read(rfd,buffer,sizeof(buffer)); //如果有内容则打印出来 if(n > 0) { buffer[n] = 0; cout “`

【Linux】进程间通信之匿名管道

这里父进程仅在子进程写入时读取,没有出现子进程写一半父进程就读取的情况,因此父子进程会进行协同,有同步和互斥性。

(一)管道中的四种情况

对管道中可能出现的四种情况做说明:

读写端正常,如果管道为空,读端将被阻塞(如上所述)。读写端正常,如果管道被写满,写端将被阻塞(在管道特性中印证)。读端正常,写端关闭,读端可以读到0,表示读到了文件结尾,不堵塞。写端正常,读端关闭,操作系统会杀死正在写入的进程,用信号SIGPIPE,即kill -13

注释掉main函数中子进程的Writer函数,它会读到文件结尾并打印done信息。

【Linux】进程间通信之匿名管道

写端每秒写入一次,读端每秒读一次,读端读5秒后退出读模式,关闭读端,然后静待5秒,等待子进程结束,然后打印它的退出码和收到的信号。

代码语言:javascript代码运行次数:0

运行复制“`javascriptint main(){ //…… if(id > 0){ //父进程 close(pipefd[1]); //关闭写端 Reader(pipefd[0]); close(pipefd[0]); //关闭读端 waitpid(id, &status, 0); cout > 8) & 0xFF 【Linux】进程间通信之匿名管道

(二)管道的特性

代码语言:javascript代码运行次数:0

运行复制“`javascript//子进程持续写入void Writer(int wfd){ string s = “this is your child”; pid_t myid = getpid(); int number = 0; char buffer[NUM]; while(1) { buffer[0] = 0; snprintf(buffer,sizeof(buffer),”%s-%d-%d”,s.c_str(),myid,number++); write(wfd,buffer,strlen(buffer)); }}//父进程每5秒读取一次数据void Reader(int rfd){ char buffer[NUM]; while(1) { sleep(5); buffer[0] = 0; ssize_t n = read(rfd,buffer,sizeof(buffer)); if(n > 0) { buffer[n] = 0; cout “`

【Linux】进程间通信之匿名管道

我们发现,读取的数据是杂乱无章的,这说明管道是面向字节流的。这与前面的说法并不矛盾,有人可能会问,这里不是还没写完就读取了吗?你看这句话是一段一段的。实际上,这里是因为缓冲区写满了,写端被阻塞,直到读取端读取数据后,写端才能继续写入。这也验证了之前的说法。

今天的分享就到这里了。

以上就是【Linux】进程间通信之匿名管道的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/73737.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月13日 23:43:24
下一篇 2025年11月14日 00:15:00

相关推荐

  • PHP代码怎么使用命名空间_ PHP命名空间声明与类导入步骤

    PHP命名空间通过namespace声明逻辑分组,use导入外部类,解决类名冲突、提升代码组织性与可读性,结合自动加载实现高效开发。 PHP命名空间主要通过 namespace 关键字来声明代码所属的逻辑分组,而 use 关键字则用于导入其他命名空间中的类、接口或函数,这样能有效避免不同代码库间因类…

    2025年12月12日
    000
  • PHP源码调试技巧分享_PHP源码调试技巧全面教程

    答案:调试PHP需结合日志、Xdebug与错误报告,生产环境应以非侵入式为主。首先利用var_dump快速验证,再通过Xdebug实现断点调试,配合error_log记录关键信息,并配置error_reporting确保开发阶段暴露问题。生产环境中优先使用日志系统(如Monolog),结合SSH隧道…

    2025年12月12日
    000
  • PHP怎么解压缩文件_PHP实现ZIP文件解压缩教程

    答案:使用PHP内置ZipArchive类可高效解压ZIP文件。首先检查zip扩展是否加载,确保目标目录存在且有写入权限,再通过open()打开ZIP文件,调用extractTo()解压并关闭资源。常见错误包括文件路径错误、权限不足、ZIP损坏等,可通过error_log、status属性及系统函数…

    2025年12月12日
    000
  • PHP数据库加密存储实现_PHP数据加密解密函数详解

    应用层加密结合密钥安全管理可实现数据库敏感数据的高安全性存储,核心是使用AES-256-CBC算法通过openssl_encrypt和openssl_decrypt函数在数据写入前加密、读取时解密,并将随机IV与密文拼接后Base64编码存储;密钥须从环境变量或KMS等安全途径获取,严禁硬编码或提交…

    2025年12月12日
    000
  • PHP代码注入检测安全加固_PHP代码注入检测系统安全加固

    答案:PHP代码注入的检测与加固需构建纵深防御体系,涵盖输入验证、参数化查询、错误处理、日志监控、最小权限原则、WAF部署及安全配置。首先对所有用户输入实施白名单验证与特殊字符过滤,优先使用PDO进行参数化查询以杜绝SQL注入;禁用eval、exec等高危函数,限制文件操作权限,分离上传目录并禁用脚…

    2025年12月12日
    000
  • PHP源码修改扩展模块_PHP源码扩展模块修改教程

    修改PHP源码扩展模块本质是通过C/C++开发独立扩展,利用Zend API与PHP内核交互,实现性能优化、底层集成或功能增强。1. 明确需求后使用ext_skel生成骨架;2. 编写C代码注册函数并处理ZVAL;3. 编译安装并配置php.ini加载so文件;4. 通过phpinfo()和测试脚本…

    2025年12月12日
    000
  • PHP怎么使用预处理语句_PHP预处理语句防注入教程

    预处理语句通过分离SQL结构与数据防止SQL注入,并提升重复执行语句的性能,PHP中主要用PDO或mysqli实现。 预处理语句在PHP中主要用于提高数据库操作的安全性,防止SQL注入攻击,并能提升性能,特别是对于重复执行的SQL语句。简单来说,就是先定义好SQL语句的结构,然后填充数据,数据库会预…

    2025年12月12日
    000
  • 跨语言AES/GCM/128加解密:PHP与Java互操作指南

    本文深入探讨了PHP与Java之间使用AES/GCM/128算法进行跨语言加解密的常见挑战与解决方案。通过分析PHP的加密逻辑,揭示了IV、密文和认证标签的编码方式,并针对Java端常见的AEADBadTagException错误,提供了关键参数(如密钥处理、IV长度和数据解析)的正确配置方法,确保…

    2025年12月12日
    000
  • PHP源码XML解析扩展_PHP源码XML解析扩展方法

    深入PHP源码扩展XML解析能力,核心是通过C语言扩展或FFI机制突破原生API性能与功能限制。首先,编写自定义C扩展可直接调用libxml2等底层库,实现流式解析、内存优化和高精度控制,适用于处理GB级XML文件;其次,PHP 7.4+的FFI支持无需编译扩展即可调用C函数,便于快速集成高性能解析…

    2025年12月12日
    000
  • PHP如何使用GD库绘图_GD库图像处理完整教程

    GD库绘图核心是通过PHP函数动态创建图像,基本流程包括创建画布、分配颜色、绘制图形文本、输出图像并释放内存;处理JPG、PNG、GIF时需注意格式特性与透明度管理;生成缩略图和水印常用imagecopyresampled()与imagecopymerge(),性能优化关键在于及时释放资源、合理设置…

    2025年12月12日
    000
  • PHP表单数据安全提交至MSSQL数据库的教程

    本文详细介绍了如何安全有效地将PHP表单数据提交至MSSQL数据库。教程首先分析了常见的数据传输问题和SQL注入风险,随后提供了使用sqlsrv扩展进行预处理语句的实践指南,确保数据安全。同时,还涵盖了表单数据获取、输入验证以及数据库连接管理等关键环节,旨在帮助开发者构建健壮的Web应用。 PHP与…

    2025年12月12日
    000
  • 在Laravel中高效扁平化与合并集合数据为单一关联数组

    本教程详细介绍了如何在Laravel应用中,将包含嵌套集合和独立字段的数据结构,通过巧妙运用map、flatten、flatMap等集合方法,以及PHP数组合并技巧,转换为一个简洁的单一关联数组。这种数据重构对于优化API响应、简化前端数据处理或满足特定数据格式要求至关重要。 理解原始数据结构与期望…

    2025年12月12日
    000
  • Laravel 集合操作:高效扁平化与合并复杂数组结构

    本文将指导如何在 Laravel 中处理复杂的集合结构,特别是如何将 map 操作产生的嵌套数组进行扁平化,并与其他键值对合并,最终生成一个单一层级的关联数组。通过使用 flatMap() 或 map() 结合 collapse() 方法,您可以高效地重塑数据结构,以满足特定的输出需求,提升代码的简…

    2025年12月12日
    000
  • Symfony Form中基于当前用户过滤EntityType字段的正确姿势

    本文旨在解决Symfony表单中EntityType字段基于当前登录用户进行过滤时遇到的Expression of type ‘AppEntityUser’ not allowed in this context错误。核心问题在于Doctrine QueryBuilder的w…

    2025年12月12日
    000
  • PHPMailer邮件发送疑难解答与最佳实践:告别发送失败和垃圾邮件

    本文旨在解决PHPMailer在邮件发送过程中常见的配置问题,包括版本过旧、SMTP加密协议与端口设置不当,以及最关键的setFrom地址伪造导致的邮件发送失败或被标记为垃圾邮件。通过提供详细的解决方案和最佳实践代码示例,帮助开发者构建稳定可靠的邮件发送功能。 phpmailer是一个功能强大且广泛…

    2025年12月12日
    000
  • 使用 RSelenium 从动态 PHP 网站提取表格数据到 R 数据框

    本教程详细介绍了如何利用 RSelenium 库从动态加载内容的 PHP 网站中提取表格数据并将其转换为 R 数据框。针对传统 rvest 或 XML 方法无法处理 JavaScript 渲染页面的问题,我们采用浏览器自动化技术,模拟用户访问并获取完整的页面源,从而准确抓取目标表格。文章提供了完整的…

    2025年12月12日
    000
  • PHPMailer邮件发送常见陷阱与最佳实践:解决From地址伪造及配置错误

    本文旨在深入探讨使用PHPMailer发送邮件时常遇到的问题,特别是由于“From”地址伪造导致的邮件被拒或进入垃圾邮件,以及不正确的SMTP配置(如过时版本、SMTPSecure值、Port类型)所引发的发送失败。我们将提供详细的解决方案、最佳实践和更新后的代码示例,帮助开发者确保邮件能够稳定、安…

    2025年12月12日
    000
  • PHP源码缓存机制实现_PHP源码缓存机制实现教程

    Opcode缓存是PHP性能优化的核心机制,通过将PHP脚本编译后的Opcode存储在共享内存中,避免每次请求重复解析和编译,显著降低CPU和I/O开销。首次请求时Zend引擎将PHP代码编译为Opcode并由OPcache等扩展存入共享内存;后续请求直接从内存加载Opcode执行,跳过文件读取与编…

    2025年12月12日
    000
  • PHP数据库迁移工具使用_PHP迁移脚本编写与执行教程

    PHP数据库迁移通过代码管理数据库变更,实现版本控制。它确保开发、测试、生产环境的数据库结构一致,提升团队协作与部署效率。主要方案有两种:一是使用Laravel等框架内置的迁移工具,通过Artisan命令生成、执行和回滚迁移文件,结合Schema构建器编写可读性强的PHP代码来定义结构变更,并支持数…

    2025年12月12日
    000
  • PHP数据库JSON数据操作_PHPJSON编码解码数据库应用

    答案:PHP通过json_encode()和json_decode()实现JSON与数据库的双向转换,适用于动态、半结构化数据存储,结合MySQL/PostgreSQL的虚拟列或GIN索引可优化查询性能,需注意输入验证、SQL注入防护及敏感信息过滤以确保安全。 在PHP应用中,将JSON数据与数据库…

    2025年12月12日
    000

发表回复

登录后才能评论
关注微信