新闻详情

新闻详情

首页 / 资讯中心 / 详情

Linux:进程间通信——匿名管道通信、命名管道通信

发布时间:2026/10/1 2:46:44来源:尧图网络
Linux:进程间通信——匿名管道通信、命名管道通信
一、通信的概念很容易理解就是两个进程可以相互进行数据的输入输出,对一块资源的共同使用或者是一个进程让另外一个进程执行不同任务等都是通信的目的我们知道进程是有独立性的那肯定不可能是在自己的进程内部的资源因为其它进程看不到,所以一定是有一块公共空间能让不同进程进行通信二、管道通信就是我们以前命令用过的 比如 ls | head -1 的竖划线就是管道为什么叫管道?因为管道通信都是单向通信一个进程只能写入数据另外一个只能读数据像我们现实中管道一样一边工厂给你输入水你自己用水龙头使用。2.1匿名管道特点:严格的单向通信(一个进程只做输入或输出)管道结构:它其实是一个内存级的file文件也就是将来的数据不会刷新到磁盘上。file文件中的内核缓冲区就是管道它与普通文件的区别就是它没有名字(也就是没有路径)其他的inode、fd等结构都有也就是说这个file也能存在在我们进程的文件描述符数组里面所以说管道的创建思想是借用了文件创建的思想也就是复用内核的结构父子进程之间的通信我们知道父子进程保持独立性的原因主要是一旦在代码中修改就会发生写实拷贝父子进程在物理内存的代码各一份所以缺点很明显:数据只能提前搞好一旦修改以后资源就不同但管道通信还真是只能父子之间的那是如何做到的呢?所以父子进程就能共用一块资源做到通信如何代码实现通信呢?那首先我们得知道一个管道文件是被进程的两个fd指向的那肯定要系统调用创建管道-pipe(int pipefd[ ]),需要传一个两个元素的数组其中pipe创建管道后 fd[0]对应读端放到fd[1]对应写端为什么要这样不是说单向通信吗?因为你不知道是将来的子进程做输入还是做输出并且将来你自己是做输入输出所以创建的子进程会拷贝父进程那它的文件描述符数组是和父进程一样的它也有两个fd指向管道分别为读端和写端将来谁要做写端那就把另外一个进程的写端给close关闭调然后自己的读端close掉不就是单向通信么下面是代码的小demo:#includestdio.h#includeunistd.h#includestring.h#includesys/wait.h#includestdlib.hintmain(){intpipefd[2]{0};intnpipe(pipefd);// 创建管道if(n0){perror(pipe);}printf(pipefd[0]: %d,pipefd[1]:%d\n,pipefd[0],pipefd[1]);// 0为读1为写intidfork();// 创建子进程if(id0){// childclose(pipefd[0]);charoutbuff[1024];intcnt5;char*msghello pipe!;while(cnt){snprintf(outbuff,sizeof(outbuff),%s %d %d\n,msg,cnt--,getpid());// snprintf会自动在末尾加\0write(pipefd[1],outbuff,strlen(outbuff));// close(pipefd[1]);// break;sleep(1);}printf(write pip over\n);exit(0);}close(pipefd[1]);charinbuff[1024];while(1){// inbuff[0]0;ssize_t nread(pipefd[0],inbuff,sizeof(inbuff)-1);// 减一是给\0留位置if(n0){inbuff[n]\0;printf(%s,inbuff);close(pipefd[0]);}// printf(%s:%ld\n,inbuff,n);// sleep(1);elseif(n0){printf(read over);break;}else{perror(read);break;}}// close(pipefd[0]);intstatus0;intridwaitpid(id,status,0);if(rid0){printf(%d,exit_code;%d,signal_code;%d\n,rid,WEXITSTATUS(status),status0x7f);}return0;}下面是总结的匿名管道的特性与情况特性:1、管道是单向通信的2、匿名管道是具有血缘关系的进程常用父子通信(继承内核资源)3、管道随进程结束而结束(本质就是判断管道的进程引用引用计数)4、管道是面向字节流的(也就是管道里的数据不一定是字符图片、音频等都有可能)字节流的说明:也就是你往管道里写多次数据但输出的数据不一定是全部的数据它是按需输出就类似于语言级缓冲区数据刷新进内核级缓冲区的特性5、管道通信对于多进程而言是有同步和互斥的关系同步:就是访问数据具有一定的顺序性,也就是访问数据需要排队(这只是简单的理解)互斥:任何时刻只允许一个进程访问资源情况(父进程为写端子进程为读端):1、父进程写的慢子进程就要阻塞(管道为空读就要阻塞),等管道有数据才读2、父进程写的快管道为满时父进程要阻塞子进程要读管道里的数据3、读端在读写端关闭读端把管道数据读完后read0说明读到了管道文件末尾4、读端关闭OS就会把写端进程给杀掉(避免浪费资源)三、命名管道命名管道有自己的路径,跟普通文件不同的是它不做刷新内核缓冲区给磁盘它的特性与匿名管道几乎差不多除了两个进程通信是毫无相关的进程无血缘关系的实现命名管道的编写创建命名管道系统调用函数:mkfifo(char* path,mode)命令创建:mkfifo 文件名c创建命名管道:框架如下:#defineMODE0666#defineTO_WRITE1#defineTO_READ2classnamed_pipe{public:named_pipe(std::string pfile_path./fifo):_pfile_path(pfile_path){}~named_pipe(){}private:std::string _pfile_path;pid_t _fd-1;};创建管道文件的路径可以随意给我这里就是当前路径1.创建管道stat函数是判断你给的这个文件是否已经存在,struct stat结构体是会返回里面的属性你需要可以通过这个结构体拿到这里有个坑是不能用open函数用只读的方式打开文件看返回值的因为对管道文件很特殊如果文件存在它会一直卡在这里直到有进程以写的方式打开了管道文件才会往后走所以如果这里用open会有bugvoidBuild_pipe(){if(IF_EXIST()){std::cout命名管道已存在不需要再次创建!!!std::endl;return;}intnmkfifo(_pfile_path.c_str(),MODE);if(n0){std::cerrmkfifo errno:errnostrerror(errno)std::endl;}std::cout命名管道创建成功!!!std::endl;}boolIF_EXIST(){// 能拿到文件的属性structstatst;intnstat(_pfile_path.c_str(),st);if(!n)returntrue;elsereturnfalse;}2.让进程拿到不同的权限voidGet_Power(intmode){if(modeTO_WRITE){_fdopen(_pfile_path.c_str(),O_WRONLY);if(_fd0){std::coutopen write end failure!!!std::endl;}}elseif(modeTO_READ){_fdopen(_pfile_path.c_str(),O_RDONLY);if(_fd0)std::coutopen read end failure!!!std::endl;}else{std::cout函数传参错误std::endl;}//下面是测试如果为管道文件使用open打开文件时不打开写端,open函数会一直堵塞if(_fd0){std::coutopen overstd::endl;}}3.删除管道文件voidDelete_namedfile(){if(!(IF_EXIST()))return;intnunlink(_pfile_path.c_str());std::cout删除管道文件成功!!!std::endl;}后面就可以创建两个进程来看了这里就展示进程server.cpp和client.cpp的代码来模拟客户端向服务端发送消息#includenamed_pipe.hpp//server.cppintmain(){named_pipe np;np.Build_pipe();np.Get_Power(TO_READ);std::string msg;while(true){charoutbuff[128];ssize_t nread(np.get_fd(),outbuff,sizeof(outbuff)-1);if(n0){outbuff[n]\0;std::coutoutbuffstd::endl;}if(n0){//客户端关闭了说明我也要结束了std::cout读取客户数据完毕!!!std::endl;break;}else{std::cerrread errostd::endl;}}np.Delete_namedfile();return0;}#includenamed_pipe.hpp//client.cppintmain(){named_pipe np;np.Get_Power(TO_WRITE);while(true){std::string msg;getline(std::cin,msg);ssize_t nwrite(np.get_fd(),msg.c_str(),msg.size());if(n0){std::cout当前客户端向服务端输入n个字节std::endl;}}return0;}
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Windows窗体应用模板:.NET Framework与现代.NET选型迁移 2026/10/1 4:40:22

Windows窗体应用模板:.NET Framework与现代.NET选型迁移

1. 从新建项目那一刻说起:两个模板的"身份证"差异在 Visual Studio 里搜索"Windows 窗体",下拉列表里通常会并排出现两条:一条写着Windows 窗体应用 (.NET Framework),另一条只写Windows 窗体应用。很多人第一…

阅读更多 →
SpringBoot+Vue精准扶贫管理系统:毕设设计与答辩全流程指南 2026/10/1 4:40:22

SpringBoot+Vue精准扶贫管理系统:毕设设计与答辩全流程指南

1. 这不是普通的CRUD系统:这个选题背后的价值判断计算机毕业设计做管理系统,听起来确实不太“性感”。SpringBoot Vue 前后端分离、数据库增删改查、登录注册、权限控制——这套组合拳在毕设圈子里快被打烂了。但“精准扶贫管理系统”这个题目&#xff…

阅读更多 →
Openclaw接入QQ完整指南:从WSL2配置到NapCat部署与排查 2026/10/1 4:40:21

Openclaw接入QQ完整指南:从WSL2配置到NapCat部署与排查

把Openclaw接进QQ这件事,我在社区里看到不少朋友卡在同一个位置:不是不会配,而是不知道整个链路里到底要起几个服务、每个报错对应哪一层。我自己前后折腾了两个周末,中间走了不少弯路,比如一度以为是QQ端被风控&#…

阅读更多 →
昆仑通态组态屏与C#上位机开发:MODBUS通信、CRC16校验及工程实战排错 2026/10/1 4:40:21

昆仑通态组态屏与C#上位机开发:MODBUS通信、CRC16校验及工程实战排错

做工业自动化项目的人,迟早会碰到这么个场景:现场一排昆仑通态触摸屏,组态画面跑得挺稳,但甲方开会时突然提了个需求——把所有设备数据汇总到办公室电脑,要历史报表、要接数据库、要对接MES。这时候光靠触摸屏本身那点…

阅读更多 →
基于Matlab的停车场出入库计时计费系统设计与实现 2026/10/1 4:40:21

基于Matlab的停车场出入库计时计费系统设计与实现

做这个课题之前,我先接了一个具体需求:校内一个二十来车位的停车场,原来的管理方式是保安在门口拿小本子记录车牌和时间,出库时人工算钱,经常出现车主说“我12点进来的”结果登记的是11点50,或者干脆记错车…

阅读更多 →
macOS LVSecurityAgent 彻底卸载指南:M1 Pro 专用四层清除法 2026/10/1 4:40:15

macOS LVSecurityAgent 彻底卸载指南:M1 Pro 专用四层清除法

1. 项目概述:这不是普通卸载,而是一场 macOS 系统清洁战“LVSecurityAgent”这名字听起来像正经安全软件,但实际用过的人基本都骂过街——它不走 App Store、不提供明确卸载入口、不响应系统偏好设置里的常规移除流程,反而在后台疯…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉