Linux进程间通信(管道,命名管道/FIFO,消息队列)

news2024/11/15 4:42:35

目录

前言

一、管道

二、命名管道/FIFO

三、消息队列


前言

前面我们学习了Linux进程编程的相关函数,也举了几个进程编程的实际应用场景;我们之前学到父进程等待子进程退出时也涉及到了一些进程间通信的概念,比如子进程调用exit函数,将退出状态返回给父进程,父进程调用某个宏可以解析子进程的退出状态;但是这种通信没有意义,因为父进程在收到退出状态时,子进程已经退出了,我们想要实现两个程序在运行的过程中能够“交流”,这就是我们这篇文章开始要学习的内容。


一、管道

管道,又称为“匿名管道”,是UNIX系统IPC(进程间通信)最古老的形式。

特点:
1.它是半双工的(即同一时间数据只能在一个方向上流动),具有固定的读端和写端。
2.它只能用于具有亲缘关系的进程之间的通信(父子进程或者兄弟进程)。
3.它可以看成是一种特殊的文件,对于它的读写也可以使用普通的readwrite 等函数。但是它不     是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。


上图可以比较好的理解管道的作用,把它比作一个“水管”,流水就是数据。更加准确一点的说法,当我们创建一个管道时,是在内核中开辟了一个空间(所以说管道是一种特殊的文件,它并不属于文件,只是这样理解),父进程从管道的一端写入,子进程从管道的另一端读出。

函数原型:

#include <unistd.h>

int pipe(int pipefd[2]);

当一个管道建立时,它会创建两个文件描述符(所以我们能用open和read函数进行操作):fd[0]是为而打开的,fd[1]是为而打开的。

返回值:
创建成功返回0,失败返回-1,并且设置errno;所以文件描述符是存在我们传入的数组里。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -代码示例:

我们先写个代码来实现功能,然后结合代码我们再来看为什么要这么写

#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main()
{
	int fd[2];//用于存放管道的文件描述符
	int pid;
	char buf[128];//存放读到的字符串

	if(pipe(fd)==-1){//创建失败
		printf("creat pipe failed\n");
	}

	pid=fork();//创建子进程

    if(pid>0){//父进程
		close(fd[0]);//关闭父进程的读端
		write(fd[1],"hello from father\n",strlen("hello from father\n"));
	}
	else{//子进程
		close(fd[1]);//关闭子进程的写端
		read(fd[0],buf,128);
		printf("read form father: %s\n",buf);
	}

	return 0;
}

运行结果:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -在跟着写代码的时候,我很疑惑为什么要关闭父进程的读端和子进程的写端,他们不是没用到吗?

当我们创建一个管道并fork出子进程后,父进程会得到两个文件描述符;

        由于子进程会拷贝父进程的代码,并且有自己的独立内存空间,所以子进程也有两个指向管道读端和写端的文件描述符,可以父写子读或子写父读,也就是说不管是谁写,都是从固定的“端口”写入,那么文章一开始理解管道的图就不太正确了。由于管道是半双工的,所以两条路不能同时选,避免干扰,要把不用的路给断开。(我的理解是:创建管道后,数据不知道要怎么走,管道要怎么连接?所以我们要把路“打通”,告诉水要怎么流)所以写代码的时候要人为的将数据走向配置好,那么缺点也显而易见了,关闭了某一端后,我们不知道该如何打开关闭的那端,所以利用管道来传输数据局限性还是比较大的。

管道读写的特性:
由于fork后我们不知道是子进程先执行还是父进程先执行,如果是子进程先运行,执行到read的时候,由于管道没有数据,所以子进程会阻塞直到管道中有数据了才会读取


二、命名管道/FIFO

FIFO,也称为命名管道,FIFO文件。

特点:
1.FIFO可以在无关的进程之间交换数据,与无名管道不同。
2.FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中。

一旦创建了一个FIFO,就可以用一般的文件I/O函数操作它。它和无名管道十分类似,只不过它是文件,往文件里写就像往管道里写一样。

函数原型:

#include <sys/stat.h>

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

返回值:
成功返回0,失败返回-1,并设置对应的errno。

参数:
        用mkfifo函数就能创建一个FIFO文件(有名管道),mode参数与open函数中的mode相同。mode记录待创建文件的访问权限,0600表示可读可写的文件。
当 open 一个FIFO时,是否设置非阻塞标志(O_NONBLOCK)的区别:
·若没有指定O_NONBLOCK(默认),只读 open 要阻塞到某个其他进程为而打开此 FIFO,只写 open 要阻塞到某个其他进程为而打开它。
·若指定了O_NONBLOCK,则只读 open 立即返回,而只写 open 将出错返回 -1 如果没有进程已经为读而打开该 FIFO,其errno置ENXIO。
一般都不设置O_NONBLOCK,因为都希望写入数据后再读,不然意义不大。

代码示例:
read.c

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    char buf[128]={0};
    
	if((mkfifo("./pipe",0600)==-1)&&errno!=EEXIST)//表示创建失败或者已经存在
	{
		printf("mkfifo failed\n");
		perror("why");//打印错误原因
	}
	
	int fd = open("./pipe",O_RDONLY);//已只读的方式打开FIFO文件,会阻塞到FIFO里有数据

    read(fd,buf,20);//从fd指向的文件里读20bytes存到buf数组里
    printf("read buf: %s\n",buf);
    
    close(fd);//别忘了关闭文件,以免造成损坏

	return 0;
}

write.c

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

int main()
{
	char *str="hello from fifo\n";//要写入的字符串
	int fd = open("./pipe",O_WRONLY);//以只写方式打开
	
	write(fd,str,strlen(str));

	close(fd);

	return 0;
}

运行结果:

我们事先编译好了read.c和write.c,可以发现FIFO文件相较于其他文件的颜色不一样,先执行read.c发现程序阻塞住了,并没有现象。此时我们打开另一个终端运行write.c,结果如下:

总结: 
        可以看到FIFO和管道十分类似,但他可以在两个不同的进程之间进行交互,而管道只能用在具有亲缘关系的进程之间;两者都是通过read和write函数来读取数据,因为FIFO是文件,所以这和我们之前学的文件编程关联性很强,对文件的操作还不熟悉的可以去看我之前写的有关文件编程的博客。


三、消息队列

消息队列,是消息的链表存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。

特点:
1.
消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级
2.消息队列独立于发送和接受进程。进程终止时,消息队列及其内容并不会被删除。
3.消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。

函数原型:

消息队列是消息的链表,链表就是一个一个的结构体链接在一起,结构体原型为:

#include <stdio.h>

struct msgbuf{
    long mtype;//消息的“名字”,必须大于0
    char mtext[1];//消息包含的数据
};

 创建/获取队列:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflq);

参数:

1.key可以理解成消息队列的“名字”,每个“消息”也有它自己的“名字”,传入大于0的32位整数(接下来的代码示例我会自己取值,通常要求此值来源于ftok返回的IPC键值)。
2.msgflq为参数为模式标志参数,使用时需要与IPC对象存取权限(如0600)进行|运算来确定消息队列的存取权限,一般传入IPC_CREAT,表示:如果内核中不存在键值与key相等的消息队列,则新建一个消息队列;如果存在这样的消息队列,返回此消息队列的标识符(后续代码示例传入IPC_CREAT|0777,表示创建可读可写可执行的消息队列)

返回值:

成功:返回消息队列的标识符
出错:-1,错误原因存于error中


接受消息:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

ssize_t msgrcv(int msgid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

 参数:

msgid:消息队列的标识符
*msgp:传入msgbuf结构体类型的地址
msgsz:收取消息用sizeof计算缓存区的大小
msgtyp:
消息的“名字”,发送消息时定义
msgflq:通常为0,即阻塞的方式


发送消息:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgsnd(int msgid, const void *msgp, ssize_t msgsz, int msgflq);

参数和接受消息类似,只不过计算发送数据的大小时用strlen函数


代码示例:

send.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>

struct msgbuf{
	long mtype;
	char mtext[128];
};

int main()
{
	struct msgbuf sendbuf={888,"message from quen\n"};//消息的“名字”为888

	int msgid=msgget(0x1234,IPC_CREAT|0777);//获取消息的标识符,消息队列的“名字”为0x1234

	msgsnd(msgid,&sendbuf,strlen(sendbuf.mtext),0);//计算要发送的数据的大小,所以传入数组名即可
	return 0;
}

read.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>

struct msgbuf{
	long mtype;
	char mtext[128];
};

int main()
{
	struct msgbuf readbuf;//存储接受到的消息

	int msgid=msgget(0x1234,IPC_CREAT|0777);//获取消息队列的标识符,队列“名字”同样为0x1234

	msgrcv(msgid,&readbuf,sizeof(readbuf.mtext),888,0);//计算接受到的数据用sizeof
	printf("read from que: %s\n",readbuf.mtext);

	return 0;
}

运行结果:

有以下要注意的几点:

1.用msgget得到的返回值才是消息队列的标识符,这和我们之前的进程标识符和文件标识符的性质是一样的,类似于“身份证”一样,而msgget的第一个参数是消息队列的“名字”。
2.读取消息队列和接受消息队列应该消息队列标识符一样,“名字”一样,消息“名字”也要一样,即同一个消息队列的同一个消息里进行数据的交互
3.关于sizeof和strlen的区别,当传入一个数组名字时,sizeof返回整个数组在内存中占用的字节数,而不是数组中存储的实际数据的长度,而strlen会返回字符串"\0"之前的字符串的长度。

在之前使用read和write函数时,由于我们是以指针来定义字符串,所以要用malloc函数来分配内存空间:

n_write是写入的数据长度,同时也是接收的长度,可见malloc时分配了char数据类型的内存大小*写入的数据长度,以免溢出又+1,因为malloc函数的返回值为void类型的指针,所以前面强转为char型的指针。

以上就是消息队列的简单使用和函数的详解,并没有拿它实现很复杂的功能,但我在编程的时候在read函数直接定义一个char型的数组,把接收到的数据直接放入数组里会出错,因此,为了避免错误,建议始终按照定义的消息结构体接收和处理消息。这样可以确保接收到的消息数据被正确解释和使用,从而避免由数据类型不匹配或消息字段处理错误引起的问题。

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

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

相关文章

AWS DMS MySQL为源端,如何在更改分区的时候避免报错

问题描述&#xff1a; 文档[1]中描述MySQL compatible Databases作为DMS任务的源端&#xff0c;不支持MySQL 分区表的 DDL 更改。 在源端MySQL进行分区添加时&#xff0c;日志里会出现如下报错&#xff1a; [SOURCE_CAPTURE ]W: Cannot change partition in table members…

2024年普通人怎么利用AI工具赚钱?

在当今这个信息爆炸的时代&#xff0c;AI技术的应用如同一股不可阻挡的潮流&#xff0c;为普通人开辟了全新的赚钱途径。以下是一些普通人就可以做的赚钱方法&#xff1a; 1、信息差模式 现在市场上AI应用工具很多&#xff0c;不是所有人都会对这些工具进行深入学习和测试&am…

网络访问(Socket/WebSocket/HTTP)

概述 HarmonyOS为用户提供了网络连接功能&#xff0c;具体由网络管理模块负责。通过该模块&#xff0c;用户可以进行Socket网络通滚、WebSocket连接、HTTP数据请求等网络通信服务。 Socket网络通信&#xff1a;通过Socket(嵌套字)进行数据通信&#xff0c;支持的协议包括UDP核…

iOS开发设计模式篇第一篇MVC设计模式

目录 1. 引言 2.概念 1.Model 1.职责 2.实现 3.和Controller通信 1.Contrller直接访问Model 2.通过委托(Delegate)模式 3.通知 4.KVO 4.设计的建议 2.View 1.职责 2.实现 3.和Controller通信 1. 目标-动作&#xff08;Target-Action&#xff09;模式 2…

matlab gui下的tcp client客户端编程框架

GUI界面 函数外定义全局变量 %全局变量 global TcpClient; %matlab作为tcpip客户端 建立连接 在“连接”按钮的回调函数下添加以下代码&#xff1a; global TcpClient;%全局变量 TcpClient tcpip(‘192.168.1.10’, 7, ‘NetworkRole’,‘client’); %连接到服务器地址和端…

免费【2024】springboot北京医疗企业固定资产管理系统的设计与实现

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

Springboot项目打包成镜像、使用docker-compose启动

Springboot项目打包成镜像、使用docker-compose启动 1、创建一个boot项目 1、添加依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSch…

Adobe Dimension(DN)安装包软件下载

目录 一、软件简介 二、软件下载 三、注意事项 四、软件功能 五、常用快捷键 快捷键&#xff1a; 一、软件简介 Adobe Dimension&#xff08;简称DN&#xff09;是Adobe公司推出的一款三维设计和渲染软件。与一般的3D绘图软件相比&#xff0c;DN在操作界面和功能上有所不…

预防大于治疗!夏季脑血管疾病高发,应该注意什么?

夏日炎炎&#xff0c;虽然气温攀升带来了一抹活力&#xff0c;却也悄悄增加了心脑血管疾病的风险。高温、高湿的环境易使人体血管扩张&#xff0c;心率加快&#xff0c;血液黏稠度上升&#xff0c;对于中老年人及已有心脑血管疾病史的人群而言&#xff0c;更是需要格外警惕。因…

项目实战--C#实现图书馆信息管理系统

本项目是要开发一个图书馆管理系统&#xff0c;通过这个系统处理常见的图书馆业务。这个系统主要功能是&#xff1a;&#xff08;1&#xff09;有客户端&#xff08;借阅者使用&#xff09;和管理端&#xff08;图书馆管理员和系统管理员使用&#xff09;。&#xff08;2&#…

Cxx Primer-chap6

什么是函数&#xff1a;A function is a block of code with a name.&#xff1a;函数调用和返回&#xff1a;&#xff0c;实例&#xff1a;名字有作用域(visible)&#xff0c;对象有生命周期(exist)&#xff1a; &#xff0c;lifetime取决于object在哪定义和如何定义&#xff…

算法题目整合4

文章目录 122. 大数减法123. 滑动窗口最大值117. 软件构建124. 小红的数组构造125. 精华帖子126. 连续子数组最大和 122. 大数减法 题目描述 以字符串的形式读入两个数字&#xff0c;编写一个函数计算它们的差&#xff0c;以字符串形式返回。输入描述 输入两个数字&#xff…

FPGA DNA 获取 DNA_PORT

FPGA DNA DNA 是 FPGA 芯片的唯一标识&#xff0c; FPGA 都有一个独特的 ID &#xff0c;也就是 Device DNA &#xff0c;这个 ID 相当于我们的身份证&#xff0c;在 FPGA 芯片生产的时候就已经固定在芯片的 eFuse 寄存器中&#xff0c;具有不可修改的属性。在 xilinx 7series…

Adobe国际认证详解-职业发展规划指南

Adobe国际认证&#xff0c;又称为Adobe Certified Professional&#xff08;简称ACP&#xff09;&#xff0c;是Adobe公司CEO签发的权威国际认证体系。这一认证体系基于Adobe核心技术及岗位实际应用操作能力的测评&#xff0c;旨在为用户提供创意软件的专业认证。 Adobe国际认证…

win11 安装 Gradle以及通过Gradle 编译Spring boot 2.7.x源码

一、win11 安装Gradle(7.5.1)&#xff1a; 1.1、下载二进制包 Gradle下载页面 1.2、配置环境变量 变量名&#xff1a;GRADLE_HOME 变量值&#xff08;二进制包解压路径&#xff09;&#xff1a;D:\develop-tool\gradle-7.5.1 变量名&#xff1a;GRADLE_USER_HOME 变量值&a…

知识表示 | 利用 Protégé 软件构建小型本体

Hi&#xff0c;大家好&#xff0c;我是半亩花海。本项目旨在利用 Protg 软件构建小型本体&#xff0c;探索本体建模的实际应用&#xff0c;特别是应用本体与上层本体之间的关系继承与映射。我们将重点理解应用本体如何继承上层本体的关系&#xff0c;以及如何通过推理机制揭示实…

线性dp.

线性dp&#xff0c;在进行动态规划中&#xff0c;常以线性的形式表现出来。 我们仍用闫氏dp法来进行求解即可 一、状态表示&#xff1a;当前的状态所代表的含义以及能用几维的形式表现出来。包括①集合&#xff0c;②属性 二、状态计算&#xff1a;如何一步一步的将状态计算出…

Hostspot2.0网络是什么?

Hotspot 2.0是一种无线网络技术标准&#xff0c;它是由Wi-Fi联盟推出的&#xff0c;旨在改善公共Wi-Fi热点的用户体验&#xff0c;简化连接流程&#xff0c;提升安全性&#xff0c;并提供更好的漫游体验。Hotspot 2.0也被称为Passpoint&#xff08;Passpoint Release 2&#xf…

Go基础编程 - 12 -流程控制

流程控制 1. 条件语句1.1. if...else 语句1.2. switch 语句1.3. select 语句1.3.1. select 语句的通信表达式1.3.2. select 的基特性1.3.3. select 的实现原理1.3.4. 经典用法1.3.4.1 超时控制1.3.4.2 多任务并发控制1.3.4.3 监听多通道消息1.3.4.4 default 实现非堵塞读写 2. …

【全网首发】小红书最新引流法:轻松留联系方式卡片,直接上演无举报窗口

大家好&#xff01;我是闷声轻创&#xff01;根据最新消息小红书卡片可能会被禁止掉&#xff0c;这对我们的引流矩阵有真不小的冲击&#xff0c;毕竟小红书作为国内领​先的年轻人的生活分享社区&#xff0c;但上有政策下有对策&#xff0c;我今天发现了一个新的留V的方法&…