Linux-----进程通讯(消息队列)

目录

相关API

1.相关数据类型

mqd_t

struct mq_attr

 struct timespec

2.相关系统调用接口

mq_open()

mq_timedsend() && mq_send()

mq_timedreceive() && mq_receive()

mq_unlink()

clock_gettime()

父子进程使用消息队列通讯

平行进程使用消息队列通讯(生产者-消费者)

 生产者(producer.c)

消费者(customer.c)


相关API

1.相关数据类型

mqd_t

该数据类型定义在mqueue.h中,是用来记录消息队列描述符的。

typedef int mqd_t;

实质上是int类型的别名

struct mq_attr
/*** @brief 消息队列的属性信息* mq_flags 标记,对于mq_open,忽略它,因为这个标记是通过前者的调用传递的* mq_maxmgs 队列可以容纳的消息的最大数量* mq_msgsize 单条消息的最大允许大小,以字节为单位* mq_curmsgs 当前队列中的消息数量,对于mq_open,忽略它*/
struct mq_attr {
long mq_flags;   /* Flags (ignored for mq_open()) */
long mq_maxmsg;  /* Max. # of messages on queue */
long mq_msgsize; /* Max. message size (bytes) */
long mq_curmsgs; /* # of messages currently in queue(ignored for mq_open()) */
};
 struct timespec
/*** @brief 时间结构体,提供了纳秒级的UNIX时间戳* tv_sec 秒* tv_nsec 纳秒*/
struct timespec {
time_t tv_sec;        /* seconds */
long   tv_nsec;       /* nanoseconds */
};

2.相关系统调用接口

mq_open()
#include <fcntl.h>    /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#include <mqueue.h>/*** @brief 创建或打开一个已存在的POSIX消息队列,消息队列是通过名称唯一标识的。** @param name 消息队列的名称* 命名规则:必须是以正斜杠/开头,以\0结尾的字符串,中间可以包含若干字符,但不能有正斜杠* @param oflag 指定消息队列的控制权限,必须也只能包含以下三者之一* O_RDONLY 打开的消息队列只用于接收消息* O_WRONLY 打开的消息队列只用于发送消息* O_RDWR 打开的消息队列可以用于收发消息* 可以与以下选项中的0至多个或操作之后作为oflag* O_CLOEXEC 设置close-on-exec标记,这个标记表示执行exec时关闭文件描述符* O_CREAT 当文件描述符不存在时创建它,如果指定了这一标记,需要额外提供mode和attr参数* O_EXCL 创建一个当前进程独占的消息队列,要同时指定O_CREAT,要求创建的消息队列不存在,否则将会失败,并提示错误EEXIST* O_NONBLOCK 以非阻塞模式打开消息队列,如果设置了这个选项,在默认情况下收发消息发生阻塞时,会转而失败,并提示错误EAGAIN* @param mode 每个消息队列在mqueue文件系统对应一个文件,mode是用来指定消息队列对应文件的权限的* @param attr 属性信息,如果为NULL,则队列以默认属性创建* @return mqd_t 成功则返回消息队列描述符,失败则返回(mqd_t)-1,同时设置errno以指明错误原因
*/
mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr);/*** @brief 当oflag没有包含O_CREAT时方可调用** @param name 同上* @param oflag 同上* @return mqd_t 同上*/
mqd_t mq_open(const char *name, int oflag);
mq_timedsend() && mq_send()

 对于 mq_send()这个方式就是发送没有超时机制,可以一直处于阻塞状态。

#include <time.h>
#include <mqueue.h>/*** @brief 将msg_ptr指向的消息追加到消息队列描述符mqdes指向的消息队列的尾部。如果消息队列已满,默认情况下,调用阻塞直至有充足的空间允许新的消息入队,或者达到abs_timeout指定的等待时间节点,或者调用被信号处理函数打断。需要注意的是,正如上文提到的,如果在mq_open时指定了O_NONBLOCK标记,则转而失败,并返回错误EAGAIN。* * @param mqdes 消息队列描述符* @param msg_ptr 指向消息的指针* @param msg_len msg_ptr指向的消息长度,不能超过队列的mq_msgsize属性指定的队列最大容量,长度为0的消息是被允许的* @param msg_prio 一个非负整数,指定了消息的优先级,消息队列中的数据是按照优先级降序排列的,如果新旧消息的优先级相同,则新的消息排在后面。* @param abs_timeout 指向struct timespec类型的对象,指定了阻塞等待的最晚时间。如果消息队列已满,且abs_timeout指定的时间节点已过期,则调用立即返回。* @return int 成功返回0,失败返回-1,同时设置errno以指明错误原因。*/
int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout);
mq_timedreceive() && mq_receive()

 mq_receive()同样的也是没有超时机制,当没有数据来的时候就处于阻塞状态。

#include <time.h>
#include <mqueue.h>/*** @brief 从消息队列中取走最早入队且权限最高的消息,将其放入msg_ptr指向的缓存中。如果消息队列为空,默认情况下调用阻塞,此时的行为与mq_timedsend同理。* * @param mqdes 消息队列描述符* @param msg_ptr 接收消息的缓存* @param msg_len msg_ptr指向的缓存区的大小,必须大于等于mq_msgsize属性指定的队列单条消息最大字节数* @param msg_prio 如果不为NULL,则用于接收接收到的消息的优先级 * @param abs_timeout 阻塞时等待的最晚时间节点,同mq_timedsend* @return ssize_t 成功则返回接收到的消息的字节数,失败返回-1,并设置errno指明错误原因*/
ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio, const struct timespec *abs_timeout);
mq_unlink()
#include <mqueue.h>
/*** @brief 清除name对应的消息队列,mqueue文件系统中的对应文件被立即清除。消息队列本身的清除必须等待所有指向该消息队列的描述符全部关闭之后才会发生。* * @param name 消息队列名称* @return int 成功返回0,失败返回-1,并设置errno指明错误原因*/
int mq_unlink(const char *name);
clock_gettime()
#include <time.h>/*** @brief 获取以struct timespec形式表示的clockid指定的时钟* * @param clockid 特定时钟的标识符,常用的是CLOCK_REALTIME,表示当前真实时间的时钟* @param tp 用于接收时间信息的缓存* @return int 成功返回0,失败返回-1,同时设置errno以指明错误原因*/
int clock_gettime(clockid_t clockid, struct timespec *tp);

父子进程使用消息队列通讯

#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>int main(int argc, char const *argv[])
{struct mq_attr attr;// 有用的参数,表示消息队列的长度attr.mq_maxmsg = 10;attr.mq_msgsize = 100;// 下面参数没什么作用,填0就行了attr.mq_flags = 0;attr.mq_curmsgs = 0;// 创建消息队列char* queue_name = "/fitz";mqd_t mqdes = mq_open(queue_name, O_RDWR | O_CREAT, 0664, &attr); // 队列文件的引用符if (mqdes == (mqd_t)-1) {perror("mq_open");exit(EXIT_FAILURE);}pid_t pid = fork();if (pid == -1) {perror("fork");exit(EXIT_FAILURE);}// 子进程---接收消息else if (pid == 0) {char recv_buf[100];struct timespec time_info;for (int i = 0;i < 5;i++) {// 情况接收缓冲器memset(recv_buf, 0, sizeof(recv_buf));clock_gettime(0, &time_info);time_info.tv_sec += 15;// 把接收的消息打印出来if(mq_timedreceive(mqdes, recv_buf, sizeof(recv_buf), 0,&time_info) == -1){perror("mq_timedreceive");}printf("子进程接受的数据是:%s\n", recv_buf);}}// 父进程---发送消息else {char send_buf[100];struct timespec time_info; // 超时时间for (int i = 0;i < 5;i++) {memset(send_buf, 0, sizeof(send_buf));sprintf(send_buf, "父进程第%d发\n", i + 1);// 获取当前时间clock_gettime(0, &time_info);time_info.tv_sec += 5; if (mq_timedsend(mqdes, send_buf, strlen(send_buf), 0, &time_info) == -1) {perror("mq_timedsend");}printf("父进程发送消息成功\n");sleep(1);}}// 不管是父进程还是子进程,都需要释放消息队列的引用close(mqdes);// 清除消息队列只需要清除一部分就行了if (pid > 0) { mq_unlink(queue_name);}printf("父子进程通讯完毕\n");return 0;
}

平行进程使用消息队列通讯(生产者-消费者)

 生产者(producer.c)

#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>int main(int argc, char const *argv[])
{struct mq_attr attr;// 有用的参数,表示消息队列的长度attr.mq_maxmsg = 10;attr.mq_msgsize = 100;// 下面参数没什么作用,填0就行了attr.mq_flags = 0;attr.mq_curmsgs = 0;// 创建消息队列char* queue_name = "/prodecer_consumer";mqd_t mqdes = mq_open(queue_name, O_RDWR | O_CREAT, 0664, &attr); // 队列文件的引用符if (mqdes == (mqd_t)-1) {perror("mq_open");exit(EXIT_FAILURE);}// 发送端接受控制台数据,发送给对方char buf[100];struct timespec time_info;while (1){memset(buf, 0, sizeof(buf));ssize_t count = read(STDIN_FILENO, buf, sizeof(buf));clock_gettime(0, &time_info);time_info.tv_sec += 5;if (count == -1) {perror("read");continue;}// ctrl+d 退出控制台的情况,发送EOF告诉对方结束了else if (count == 0) {printf("EOF ,exit \n");char eof = EOF;if (mq_timedsend(mqdes, &eof, 1, 0, &time_info) == -1) {perror("mq_timedsend");}break;}// 正常发送else {if (mq_timedsend(mqdes, buf, strlen(buf), 0, &time_info) == -1) {perror("mq_timedsend");}printf("发送成功\n");}}printf("发送端关闭\n");close(mqdes); // 关闭描述符return 0;
}

消费者(customer.c)

#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>int main(int argc, char const *argv[])
{struct mq_attr attr;// 有用的参数,表示消息队列的长度attr.mq_maxmsg = 10;attr.mq_msgsize = 100;// 下面参数没什么作用,填0就行了attr.mq_flags = 0;attr.mq_curmsgs = 0;// 创建消息队列char* queue_name = "/prodecer_consumer";mqd_t mqdes = mq_open(queue_name, O_RDWR | O_CREAT, 0664, &attr); // 队列文件的引用符if (mqdes == (mqd_t)-1) {perror("mq_open");exit(EXIT_FAILURE);}// 发送端接受控制台数据,发送给对方char buf[100];struct timespec time_info;while (1){memset(buf, 0, sizeof(buf));clock_gettime(0, &time_info);time_info.tv_sec += 15;if (mq_timedreceive(mqdes, buf, sizeof(buf), NULL, &time_info) == -1) {perror("mq_timedreceived");}// 判断数据是否EOF结束if (buf[0] == EOF) {printf("生产者发送了结束信息,结束通讯\n");break;}else {printf("接收的消息:%s\n", buf);}}printf("接收端关闭\n");close(mqdes); // 关闭描述符// 这里选择消费者来结束队列,这样是比较合理的,因为最后一个信息EOF是被消费者接受到的,在此之前队列必须存在mq_unlink(queue_name); // 清除消息队列return 0;
}

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

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

相关文章

【微服务】面试题 5、分布式系统理论:CAP 与 BASE 详解

分布式系统理论&#xff1a;CAP 与 BASE 详解 一、CAP 定理 背景与定义&#xff1a;1998 年由加州大学科学家埃里克布鲁尔提出&#xff0c;分布式系统存在一致性&#xff08;Consistency&#xff09;、可用性&#xff08;Availability&#xff09;、分区容错性&#xff08;Part…

数据结构与算法之二叉树: LeetCode 572. 另一棵树的子树 (Ts版)

另一棵树的子树 https://leetcode.cn/problems/subtree-of-another-tree/description/ 描述 给你两棵二叉树 root 和 subRoot检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false二叉树 tree …

NineData云原生智能数据管理平台新功能发布|2024年12月版

本月发布 7 项更新&#xff0c;其中重点发布 2 项、功能优化 5 项。 重点发布 数据库 Devops - Oracle 非表对象支持可视化创建与管理 Oracle 非表对象&#xff0c;包括视图&#xff08;View&#xff09;、包&#xff08;Package&#xff09;、存储过程&#xff08;Procedur…

[Unity]MacOS下开发Unity

需要的插件 我使用的是vscode&#xff0c;经过长时间的使用我发现一个问题就是很多插件都是动态的在变化的&#xff0c;不是一成不变的&#xff0c;可能是重构&#xff0c;可能直接换了其他的工具。 所以这个插件也会是更新的状态。 2025年01月08日更新 .NET Install Tool (…

项目开发实践——基于SpringBoot+Vue3实现的在线考试系统(五)

文章目录 一、学生管理模块功能实现1、添加学生功能实现1.1 页面设计1.2 前端功能实现1.3 后端功能实现1.4 效果展示2、学生管理功能实现2.1 页面设计2.2 前端功能实现2.3 后端功能实现2.3.1 后端查询接口实现2.3.2 后端编辑接口实现2.3.3 后端删除接口实现2.4 效果展示二、代码…

实现一个VSCode插件(从创建到发布)

实现一个自己的VSCode 插件 本文将以 yo 为例&#xff0c; 实现一个 VS Code 插件 从创建到发布。 文章目录 实现一个自己的VSCode 插件1. 初始化项目2. 项目结构3. 实现插件功能4. 测试和运行插件5. 发布6. 下载自己发布的插件 1. 初始化项目 首先&#xff0c;我们需要安装 …

Unity TextMesh Pro入门

概述 TextMesh Pro是Unity提供的一组工具&#xff0c;用于创建2D和3D文本。与Unity的UI文本和Text Mesh系统相比&#xff0c;TextMesh Pro提供了更好的文本格式控制和布局管理功能。 本文介绍了TMP_Text组件和Tmp字体资产(如何创建字体资产和如何解决缺字问题),还有一些高级功…

【教程】数据可视化处理之2024年各省GDP排名预测!

过去的一年里&#xff0c;我国的综合实力显著提升&#xff0c;在新能源汽车、新一代战机、两栖攻击舰、航空航天、芯片电子、装备制造等领域位居全球前列。虽然全国各省市全年的经济数据公布还需要一段时间&#xff0c;但各地的工业发展数据&#xff0c;财政收入数据已大概揭晓…

后端:Spring(IOC、AOP)

文章目录 1. Spring2. IOC 控制反转2-1. 通过配置文件定义Bean2-1-1. 通过set方法来注入Bean2-1-2. 通过构造方法来注入Bean2-1-3. 自动装配2-1-4. 集合注入2-1-5. 数据源对象管理(第三方Bean)2-1-6. 在xml配置文件中加载properties文件的数据(context命名空间)2-1-7. 加载容器…

从CentOS到龙蜥:企业级Linux迁移实践记录(龙蜥开局)

引言&#xff1a; 在我们之前的文章中&#xff0c;我们详细探讨了从CentOS迁移到龙蜥操作系统的基本过程和考虑因素。今天&#xff0c;我们将继续这个系列&#xff0c;重点关注龙蜥系统的实际应用——特别是常用软件的安装和配置。 龙蜥操作系统&#xff08;OpenAnolis&#…

一.项目课题 <基于TCP的文件传输协议实现>

客户端代码 需要cJSON.c文件和cJSON.h文件 在这里插入代码片#include "myheadth.h" #include "myfun.h"#define TIME 10 int sockfd; void heartbeat(int signum) {cJSON* root cJSON_CreateObject();cJSON_AddStringToObject(root,"request"…

Type-C双屏显示器方案

在数字化时代&#xff0c;高效的信息处理和视觉体验已成为我们日常生活和工作的关键需求。随着科技的进步&#xff0c;一款结合了便携性和高效视觉输出的设备——双屏便携屏&#xff0c;逐渐崭露头角&#xff0c;成为追求高效工作和娱乐体验人群的新宠。本文将深入探讨双屏便携…

计算机视觉算法实战——车道线检测

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​​​​​​ ​​​​​​​​​​​​ ​​​​​ 车道线检测是计算机视觉领域的一个重要研究方向&#xff0c;尤其在自动驾驶和高级驾驶辅助…

【微服务】面试 3、 服务监控 SkyWalking

微服务监控的原因 问题定位&#xff1a;在微服务架构中&#xff0c;客户端&#xff08;如 PC 端、APP 端、小程序等&#xff09;请求后台服务需经过网关再路由到各个微服务&#xff0c;服务间可能存在多链路调用。当某一微服务挂掉时&#xff0c;在复杂的调用链路中难以迅速确定…

【MySQL数据库】基础总结

目录 前言 一、概述 二、 SQL 1. SQL通用语法 2. SQL分类 3. DDL 3.1 数据库操作 3.2 表操作 4. DML 5. DQL 5.1 基础查询 5.2 条件查询 5.3 聚合函数 5.4 分组查询 5.5 排序查询 5.6 分页查询 6. DCL 6.1 管理用户 6.2 权限控制 三、数据类型 1. 数值类…

aws(学习笔记第二十三课) step functions进行开发(lambda函数调用)

aws(学习笔记第二十三课) 开发step functions状态机的应用程序 学习内容&#xff1a; step functions状态机的概念开发简单的step functions状态机 1. step functions状态机概念 官方说明文档和实例程序 AWS的官方给出了学习的链接和实例程序。使用SAM创建step functions 借…

【Docker】入门教程

目录 一、Docker的安装 二、Docker的命令 Docker命令实验 1.下载镜像 2.启动容器 3.修改页面 4.保存镜像 5.分享社区 三、Docker存储 1.目录挂载 2.卷映射 四、Docker网络 1.容器间相互访问 2.Redis主从同步集群 3.启动MySQL 五、Docker Compose 1.命令式安装 …

算法练习7——拦截导弹的系统数量求解

题目描述 某国为了防御敌国的导弹袭击&#xff0c;发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷&#xff1a;虽然它的第一发炮弹能够到达任意的高度&#xff0c;但是以后每一发炮弹都不能高于前一发的高度。 假设某天雷达捕捉到敌国的导弹来袭。由于该系统还在试用…

如何使用高性能内存数据库Redis

一、详细介绍 1.1、Redis概述 Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的、内存中的数据结构存储系统&#xff0c;它可以用作数据库、缓存和消息中间件。Redis支持多种类型的数据结构&#xff0c;如字符串&#xff08;strings&#xff09;、哈希&am…

【Linux系列】`find / -name cacert.pem` 文件搜索

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…