news 2026/6/10 0:36:00

Linux 进程间通信---命名管道

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux 进程间通信---命名管道

1.命名管道的原理

1,如果是具有血缘关系的进程,想要通信我们可以使用匿名管道,如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。

2.在内核中,操作系统会打开一个文件,即在内核中,仅有一个文件的inode结构体,文件的files_operations结构体,一个内核级别的文件缓冲区,那么由于这两个进程可能会有不同的打开文件的方式,并且两个文件的执行流不同,读取写入到文件的位置可能也不同,所以分别会给这两个进程各自分配一个文件打开对象。

3.与匿名管道不同,进程间的通信本质是让不同的进程看到同一份资源,在匿名管道中,子进程继承了父进程的文件描述符表,父子进程一个关闭读端,一个关闭写端,从而实现进程间的通信,命名管道这里,两个不同的进程以只读和只写的方式打开文件,也达到了看到同一份资源的目的。

4.那么两个进程如何知道它们两个打开的是同一个文件?因为进行打开的时候是采用的是同路径下的同一个文件名 = 路径 + 文件名 = 具有唯一性。

5.同样的,这个命名管道也管道它也具有管道的特征,即单向通信,并且不需要将缓冲区的内容刷新到磁盘上,命名管道同样也是一个文件,这个文件是内存级文件。

2.创建命名管道

命名管道可以从命令行上创建,命令行方法是使用下面这个命令:

mkfifo filename


命名管道也可以从程序里创建,相关函数有:

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

mkfifo需要传参,第一个参数传参命名文件的路径,第二个传参命名文件的权限模式,mkfifo的返回值是一个int的变量,如果mkfifo创建命名管道成功,那么就会返回0,如果没有创建成功,创建失败了,那么就会返回-1,并且设置对应的错误码。

1 #include<stdio.h> 2 #include<sys/stat.h> 3 int main(int argc, char *argv[]) 4 { 5 mkfifo("myfifo",0644); 6 return 0; 7 }

删除命名管道可以使用unlink。

3.命名管道的4种情况

读写端正常,管道为空,读端就要阻塞,可以有效保护数据安全

读写端正常, 管道满了,写端就要阻塞,可以有效保护数据安全

读端正常读,写端关闭,读端就会读到0,代表读到了文件(pipe)结束,读端退出,不会阻塞

写端正常写,读端关闭,操作系统就要通过13号信号杀掉正在写入的写端进程

4.进程间编码的实现

makefile

1 .PHONY:all 2 all:client server 3 4 client:client.cpp 5 g++ -o $@ $^ -g -std=c++11 6 server:server.cpp 7 g++ -o $@ $^ -g -std=c++11 8 .PHONY:clean 9 clean: 10 rm -f client server

生成client和server可执行程序

pipename.hpp

#pragma once #include<iostream> #include<stdio.h> #include<stdlib.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include<string> #include<string.h> #define FILE "./log.txt" #define MODE 0644 enum { FIFO_CREATE_ERR=1, FIFO_DELETE_ERR, FIFO_OPEN_ERR }; class Init { public: Init() { int n=mkfifo(FILE,MODE); if(n<0) { perror("mkfifo"); exit(FIFO_CREATE_ERR); } } ~Init() { int m=unlink(FILE); if(m<0) { perror("mkfifo"); exit(FIFO_DELETE_ERR); } } };

将创建管道文件封装为一个类,创建类时自动创建命名管道。

client.cpp

#include"./pipe.hpp" int main() { int fd=open(FILE,O_WRONLY); if(fd<0) { perror("open"); exit(FIFO_OPEN_ERR); } std::cout<<"clinet open success"<<std::endl; std::string line; while(true) { std::cout<<"Pliease enter#"; getline(std::cin,line); int n=write(fd,line.c_str(),line.size()); } close(fd); return 0; }

以只写模式打开文件,不断的从键盘获取数据发送给文件。

server.cpp

#include"./pipename.hpp" int main() { Init p; int fd=open(FILE,O_RDONLY); if(fd<0) { perror("open"); exit(FIFO_OPEN_ERR); } while(true) { char buff[1024]; int n=read(fd,buff,sizeof(buff)); if(n>0) { buff[n]='\0'; std::cout<<"client say#"<<buff<<std::endl; } else { break; } } close(fd); return 0; }

以只读模式打开,并且打印在显示器上面,进程退出时,命名管道也会自动被删除。

运行结果:

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 1:46:23

Docker实战:镜像上传至华为云SWR并拉取私有镜像全流程详解

文章目录1. 实操概述2. 实操步骤2.1 获取华为云SWR访问凭证2.1.1 登录华为云2.1.2 进入容器镜像服务2.1.3 创建组织2.1.4 获取登录指令2.2 给本地镜像打标签2.3 登录华为云SWR2.4 推送镜像到华为云SWR2.5 在华为云SWR查看我的镜像2.6 从华为云SWR下载私有镜像2.6.1 获取华为云S…

作者头像 李华
网站建设 2026/6/9 1:43:20

使用LabVIEW远程操控信号发生器操作指南

手把手教你用LabVIEW远程控制信号发生器&#xff1a;从连接到实战的完整指南在实验室里&#xff0c;你是否也曾一遍遍手动调节信号发生器的频率、幅值&#xff0c;再切换波形、打开输出&#xff1f;重复操作不仅耗时&#xff0c;还容易出错。尤其当测试需要连续跑几十轮参数组合…

作者头像 李华
网站建设 2026/5/20 13:48:29

14、基于MDA的可执行UML组件开发方法

基于MDA的可执行UML组件开发方法 在当今的软件开发领域,服务导向的组件模型逐渐成为构建动态适应应用程序的关键。然而,构建这类组件面临着诸多挑战,尤其是服务导向框架的复杂性使得组件开发变得困难。本文将介绍一种基于MDA(Model-Driven Architecture)的方法,用于开发…

作者头像 李华
网站建设 2026/5/30 16:59:51

用Dify构建知识库问答机器人,内部培训效率翻倍

用Dify构建知识库问答机器人&#xff0c;内部培训效率翻倍 在一家快速扩张的科技公司里&#xff0c;HR每天要重复回答上百次“年假怎么申请”“试用期多久”这类问题&#xff1b;新员工入职一周还在翻找IT系统的操作手册&#xff1b;而最新的合规政策发布后&#xff0c;不同部门…

作者头像 李华
网站建设 2026/5/31 16:48:39

MDK下C语言堆栈溢出检测方法:实战调试指南

MDK下C语言堆栈溢出检测实战&#xff1a;从理论到调试的完整指南你有没有遇到过这样的情况&#xff1f;设备运行得好好的&#xff0c;突然毫无征兆地复位&#xff0c;日志停在某个函数调用前&#xff0c;而代码里又没明显的错误。查了电源、看中断、翻寄存器——最后发现&#…

作者头像 李华
网站建设 2026/6/9 21:24:56

6、面向对象编程中的继承、关系与模块化深度解析

面向对象编程中的继承、关系与模块化深度解析 1. 继承机制概述 在编程世界里,继承是一个核心概念。不同的编程语言对继承的支持方式有所不同。像 Eiffel 和 C++ 支持多继承,而 Java 在类层面只支持单继承,不过 Java 中多继承的概念常可通过命名接口来替代。 在使用继承时…

作者头像 李华