【Orange Pi 5与Linux系统编程】-POSIX消息队列

Linux系统中的POSIX消息队列编程

文章目录

  • Linux系统中的POSIX消息队列编程
    • 1、POSIX 消息队列
    • 2、Linux 中的 POSIX 消息队列命名
    • 3、POSIX 消息队列调用
      • 3.1 mq_open, mq_close
      • 3.2 mq_timed_send、mq_send、mq_timed_receive、mq_receive
      • 3.3 mq_notify
      • 3.4 mq_unlink
      • 3.5 mq_getattr, mq_setattr
    • 4、进程间通过消息队列通信
      • 4.1 服务器端代码实现
      • 4.2 客户端代码实现
      • 4.3 程序运行结果

本文将详细介绍如何在Linux中进行POSIX队列编程。

1、POSIX 消息队列

POSIX.1b 标准 (IEEE Std 1003.1b-1993) 中引入了 POSIX 进程间通信 (IPC),用于实时扩展。 自版本 2.6.6(2004 年 5 月)以来,POSIX 消息队列已在 Linux 中可用。 POSIX IPC 调用符合标准,但在较旧的类 Unix 系统上可能不可用。 与System V IPC调用相比,POSIX IPC调用具有更清晰的界面并且更易于使用。

2、Linux 中的 POSIX 消息队列命名

System V 消息队列使用通过 ftok 函数调用获得的键来标识。 POSIX 消息队列使用名称字符串进行标识。 在 Linux 上,POSIX 队列被命名为以正斜杠 (/) 开头、后跟一个或多个字符(其中没有一个是斜杠)并以空字符结尾的字符串。 任何知道队列名称并具有适当权限的进程都可以从队列发送或接收消息,并对其执行其他操作。

3、POSIX 消息队列调用

在 Linux 上使用 POSIX 消息队列的程序必须使用编译器选项 -lrt 与实时库 librt 链接。 函数调用名称以前缀 mq_ 开头。

3.1 mq_open, mq_close

#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>mqd_t mq_open (const char *name, int oflag);
mqd_t mq_open (const char *name, int oflag, mode_t mode,struct mq_attr *attr);

mq_open 函数用于打开 POSIX 队列。 第一个参数指定队列名称,如上面前面的段落中所述。 第二个参数是一个标志,可以是 O_RDONLY(用于接收消息)、O_WRONLY(用于发送消息)以及 O_RDWR(用于队列上的发送和接收操作)。 更多值可以与该标志进行“或”运算。 您可以指定 O_NONBLOCK 以非阻塞模式使用队列。 默认情况下,如果队列已满,mq_send 将阻塞,如果队列中没有消息,mq_receive 将阻塞。 但如果在 oflag 中指定了 O_NONBLOCK,则在这些情况下调用将立即返回,并将 errno 设置为 EAGAIN。

如果指定 O_CREAT 作为 oflag 的一部分,则创建队列(如果队列尚不存在)。 如果您与 O_CREAT 一起指定 O_EXCL,并且队列存在,则 mq_open 将失败,并将 errno 设置为 EEXIST。 如果在 oflag 中指定了 O_CREAT,则 mq_open 的第二种形式必须与两个附加参数一起使用。 在这种情况下,模式指定队列的权限,并且指向 struct mq_attr 的指针给出消息队列的属性。 如果该指针为NULL,则创建具有默认属性的队列。

struct mq_attr {long mq_flags;       /* Flags: 0 or O_NONBLOCK */long mq_maxmsg;      /* Max. # of messages on queue */long mq_msgsize;     /* Max. message size (bytes) */ long mq_curmsgs;     /* # of messages currently in queue */
};       

mq_open 中指针作为 attr 传递的结构体中 mq_maxmsg 的值应小于或等于 /proc 接口文件 /proc/sys/fs/mqueue/msg_max 中的值(文件中的默认值为 10)。 同样,mq_msgsize 的值应小于文件 /proc/sys/fs/mqueue/msgsize_max 中的值,文件中的默认值为 8192 字节。 对于特权进程,这些限制将被忽略。

如果 mq_open 调用成功,则返回消息队列描述符。 消息队列描述符可以在队列的后续调用中使用。

mq_close 调用如下:

#include <mqueue.h>int mq_close (mqd_t mqdes);

mq_close 调用关闭消息队列描述符 mqdes。

3.2 mq_timed_send、mq_send、mq_timed_receive、mq_receive

#include <mqueue.h>int mq_send (mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio);

mq_send 用于将消息发送到描述符 mqdes 引用的队列。 msg_ptr 指向消息缓冲区。 msg_len 是消息的大小,它应该小于或等于队列的消息大小。 msg_prio是消息优先级,它是一个非负数,指定消息的优先级。 消息按照消息优先级降序放置在队列中,较旧的消息优先于较新的消息。 如果队列已满,mq_send 将阻塞,直到队列上有空间,除非为消息队列启用了 O_NONBLOCK 标志,在这种情况下,mq_send 立即返回,并将 errno 设置为 EAGAIN。

#include <time.h>
#include <mqueue.h>int mq_timedsend (mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout);

mq_timedsend 的工作方式与 mq_send 类似,不同之处在于,如果队列已满并且未指定 O_NONBLOCK 标志,则在 abs_timeout 指向的时间发生超时,并且 mq_timedsend 返回。 值得注意的是,时间参数是自纪元 1970 年 1 月 1 日 00:00:00 +0000 UTC 以来的绝对时间(以秒和纳秒为单位)。 此外,如果队列已满并且指定的时间已过,mq_timedsend 会立即返回。 指定超时的结构如下,

struct timespec {time_t tv_sec;        /* seconds */ long   tv_nsec;       /* nanoseconds */
};    

接下来,我们调用 mq_receivemq_timedreceive 来接收消息。

#include <mqueue.h>ssize_t mq_receive (mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio);

mq_receive 从描述符 mqdes 引用的队列接收消息。 最高优先级中最旧的将从队列中删除,并传递给 msg_ptr 指向的缓冲区中的进程。 msg_len 是缓冲区的长度(以字节为单位),它必须大于队列的最大消息大小(即 mq_msgsize 属性)。 如果指针msg_prio不为空,则将接收到的消息的优先级存储在其指向的整数中。 mq_receive 的默认行为是如果队列中没有消息则阻塞。 但是,如果为队列启用了 O_NONBLOCK 标志,并且队列为空,则 mq_receive 将立即返回,并将 errno 设置为 EAGAIN。 成功时,mq_receive 返回 msg_ptr 指向的缓冲区中接收到的字节数。

#include <time.h>
#include <mqueue.h>ssize_t mq_timedreceive (mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio, const struct timespec *abs_timeout);

mq_timedreceive 与 mq_receive 相同,只是它有一个指示超时的附加参数。 如果队列的 O_NONBLOCK 标志未启用且队列为空,则 mq_timedreceive 将在出现 abs_timeout 指向的时间时返回。 如上所述,abs_timeout 指向的时间是自纪元 1970 年 1 月 1 日 00:00:00 +0000 UTC 以来以秒数和纳秒数指定的绝对时间。

3.3 mq_notify

#include <mqueue.h>int mq_notify (mqd_t mqdes, const struct sigevent *sevp);

mq_notify 用于在 mqdes 引用的空队列上注册或取消注册消息到达的异步通知。

3.4 mq_unlink

#include <mqueue.h>int mq_unlink(const char *queue_name);

mq_unlink 删除名为queue_name 的队列。

3.5 mq_getattr, mq_setattr

#include <mqueue.h>int mq_getattr(mqd_t mqdes, struct mq_attr *attr);int mq_setattr(mqd_t mqdes, const struct mq_attr *newattr,struct mq_attr *oldattr);

mq_getattr 函数获取描述符 mqdes 的消息队列的属性结构 struct mq_attr。 类似地,函数 mq_setattr 用于设置队列的属性。 但是,可以使用 mq_setattr 修改的唯一属性是 mq_flags 中的 O_NONBLOCK 标志。 newattr 指向的结构中的其他字段将被忽略。 如果oldattr不为空,则队列属性的先前值将返回到它指向的结构中。

4、进程间通过消息队列通信

下面的示例演示了在 Linux 中使用 POSIX 消息队列在服务器和客户端之间进行进程间通信。 服务器管理令牌号,这些令牌号可以是航班的座位号或类似的东西。 服务器的工作是根据请求向客户端提供令牌号。 在典型场景中,可能有多个客户端向服务器请求令牌编号。 客户端知道服务器的消息队列名称。 每个客户端都有自己的消息队列,服务器在其中发布响应。 当客户端发送请求时,它会发送其消息队列名称。 服务器打开客户端的消息队列并发送其响应。 客户端从其消息队列中获取响应并读取其中的令牌号。 流程架构如下所示。

在这里插入图片描述

4.1 服务器端代码实现

/** server.c: Server program*           to demonstrate interprocess commnuication*           with POSIX message queues*/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>#define SERVER_QUEUE_NAME   "/sp-example-server"
#define QUEUE_PERMISSIONS 0660
#define MAX_MESSAGES 10
#define MAX_MSG_SIZE 256
#define MSG_BUFFER_SIZE MAX_MSG_SIZE + 10int main (int argc, char **argv)
{mqd_t qd_server, qd_client;   // queue descriptorslong token_number = 1; // next token to be given to clientprintf ("Server: Hello, World!\n");struct mq_attr attr;attr.mq_flags = 0;attr.mq_maxmsg = MAX_MESSAGES;attr.mq_msgsize = MAX_MSG_SIZE;attr.mq_curmsgs = 0;if ((qd_server = mq_open (SERVER_QUEUE_NAME, O_RDONLY | O_CREAT, QUEUE_PERMISSIONS, &attr)) == -1) {perror ("Server: mq_open (server)");exit (1);}char in_buffer [MSG_BUFFER_SIZE];char out_buffer [MSG_BUFFER_SIZE];while (1) {// get the oldest message with highest priorityif (mq_receive (qd_server, in_buffer, MSG_BUFFER_SIZE, NULL) == -1) {perror ("Server: mq_receive");exit (1);}printf ("Server: message received.\n");// send reply message to clientif ((qd_client = mq_open (in_buffer, O_WRONLY)) == 1) {perror ("Server: Not able to open client queue");continue;}sprintf (out_buffer, "%ld", token_number);if (mq_send (qd_client, out_buffer, strlen (out_buffer) + 1, 0) == -1) {perror ("Server: Not able to send message to client");continue;}printf ("Server: response sent to client.\n");token_number++;}
}

4.2 客户端代码实现

/** client.c: Client program*           to demonstrate interprocess communication*           with POSIX message queues*/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>#define SERVER_QUEUE_NAME   "/sp-example-server"
#define QUEUE_PERMISSIONS 0660
#define MAX_MESSAGES 10
#define MAX_MSG_SIZE 256
#define MSG_BUFFER_SIZE MAX_MSG_SIZE + 10int main (int argc, char **argv)
{char client_queue_name [64];mqd_t qd_server, qd_client;   // queue descriptors// create the client queue for receiving messages from serversprintf (client_queue_name, "/sp-example-client-%d", getpid ());struct mq_attr attr;attr.mq_flags = 0;attr.mq_maxmsg = MAX_MESSAGES;attr.mq_msgsize = MAX_MSG_SIZE;attr.mq_curmsgs = 0;if ((qd_client = mq_open (client_queue_name, O_RDONLY | O_CREAT, QUEUE_PERMISSIONS, &attr)) == -1) {perror ("Client: mq_open (client)");exit (1);}if ((qd_server = mq_open (SERVER_QUEUE_NAME, O_WRONLY)) == -1) {perror ("Client: mq_open (server)");exit (1);}char in_buffer [MSG_BUFFER_SIZE];printf ("Ask for a token (Press <ENTER>): ");char temp_buf [10];while (fgets (temp_buf, 2, stdin)) {// send message to serverif (mq_send (qd_server, client_queue_name, strlen (client_queue_name) + 1, 0) == -1) {perror ("Client: Not able to send message to server");continue;}// receive response from serverif (mq_receive (qd_client, in_buffer, MSG_BUFFER_SIZE, NULL) == -1) {perror ("Client: mq_receive");exit (1);}// display token received from serverprintf ("Client: Token received from server: %s\n\n", in_buffer);printf ("Ask for a token (Press ): ");}if (mq_close (qd_client) == -1) {perror ("Client: mq_close");exit (1);}if (mq_unlink (client_queue_name) == -1) {perror ("Client: mq_unlink");exit (1);}printf ("Client: bye\n");exit (0);
}

4.3 程序运行结果

服务器和客户端程序需要使用-lrt选项进行编译。 首先,运行服务器。 然后可以运行一个或多个客户端进行测试。 对于每个队列,都会在 /dev/mqueue 目录(在 Linux 中)中创建一个文件。

服务器端:

$ # server
$ gcc server.c -o server -lrt
$ gcc client.c -o client -lrt
$ ./server
Server: Hello, World!
Server: message received.
Server: response sent to client.
Server: message received.
Server: response sent to client.
Server: message received.
Server: response sent to client.
Server: message received.
Server: response sent to client.
...
...

客户端:

$ ./client
Ask for a token (Press ): 
Client: Token received from server: 1Ask for a token (Press ): 
Client: Token received from server: 2Ask for a token (Press ): 
Client: Token received from server: 4

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

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

相关文章

【Java】已解决java.lang.FileNotFoundException异常

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决java.lang.FileNotFoundException异常 在Java编程中&#xff0c;java.lang.FileNotFoundException是一个常见的异常&#xff0c;它通常表示程序试图打开一个不存在的文件、文…

使用Let‘s Encrypt 申请通配符证书

为什么不使用阿里云/腾讯云等公有云厂商提供的免费证书? 上篇介绍了从阿里云上面申请免费证书,有效期一年 为网站配置https证书 公有云提供的证书不支持通配符&#xff0c;只支持某个确定的解析。 不管是二级域名还是三级域名&#xff0c;只要是具体的确定的地址&#xff0c;都…

号外!号外!全网第一手Android P刘海屏适配大揭秘,唯一Kotlin算法

如下图所示&#xff1a; 4.2.适配刘海屏 在刘海屏调试打开之后&#xff0c;浏览应用的所有页面&#xff0c;测试所有遮挡问题&#xff0c;或者是下移导致的问题&#xff0c;对有问题的页面进行布局适配。适配方案如下&#xff1a; Google 提供的适配方案&#xff0c;可以设置…

使用VisualBox+Vagrant搭建Centos虚拟机环境

1.下载并安装VisualBox&#xff1b; 2.下载并安装Vagrant; 3.打开cmd窗口&#xff0c;执行命令vagrant init centos/7&#xff0c;初始化centos环境&#xff0c;该步骤受网络带宽影响&#xff0c;可能挂级30分钟到1个小时&#xff1b; 4.启动虚拟机&#xff1a;vagrant up&…

数据库理论大题与编译原理大题(笔记)

目录 数据库&#xff08;求最小函数依赖&#xff09; 数据库&#xff08;求属性集的闭包和候选码&#xff09; 编译原理&#xff08;NFA ——> DFA&#xff09; 编译原理&#xff08;识别文法的活前缀 DFA 和 LR(0) 分析表&#xff09; 哈哈&#xff01;这是本人作者才…

WordPress强大多功能主题模板The7 v9.16.0

模板介绍 The7可以与WPBakery Page Builder&#xff08;原Visual Composer&#xff09;和Ultimate Addons的完全无缝集成。它也与大多数流行的插件完全兼容&#xff0c;例如WooCommerce&#xff0c;WPML&#xff0c;Yoast SEO&#xff0c;All in One WP Migration&#xff0c;…

Windows系统下安装RabbitMQ详细步骤

声明&#xff1a;原文参考链接出自&#xff1a; 如何在Windows系统下安装RabbitMQ_rabbitmq windows安装-CSDN博客 https://zhuanlan.zhihu.com/p/693160757 一、RabbitMQ安装软件资源准备 因为RabbitMQ是Erlang语言开发的&#xff0c;因此安装Erlang环境在进行安装RbbitMQ的…

无需破解,打开就是旗舰版!

在当今快节奏的工作环境里&#xff0c;有效的视觉沟通变得至关重要。流程图、思维导图、组织结构图等图表能够帮助我们以清晰、直观的方式传达复杂信息。而Wondershare Edraw Max正是这样一款强大的绘图工具&#xff0c;它能够帮助用户轻松创建各种专业图表。 软件链接&#x…

基于springboot websocket和okhttp实现消息中转

1、业务介绍 消息源服务的消息不能直接推给用户侧&#xff0c;用户与中间服务建立websocket连接&#xff0c;中间服务再与源服务建立websocket连接&#xff0c;源服务的消息推给中间服务&#xff0c;中间服务再将消息推送给用户。流程如下图&#xff1a; 此例中我们定义中间服…

解析PDF文件中的图片为文本

解析PDF文件中的图片为文本 1 介绍 解析PDF文件中的图片&#xff0c;由两种思路&#xff0c;一种是自己读取PDF文件中的图片&#xff0c;然后用OCR解析&#xff0c;例如&#xff1a;使用PyMuPDF读取pdf文件&#xff0c;再用PaddleOCR或者Tesseract-OCR识别文字。另一种使用第…

信息学奥赛初赛天天练-32-CSP-J2022基础题-中缀表达式、后缀表达式、哈夫曼编码、连通图、邻居矩阵、完全二叉树、数组存储

PDF文档公众号回复关键字:20240623 2022 CSP-J 选择题 单项选择题&#xff08;共15题&#xff0c;每题2分&#xff0c;共计30分&#xff1a;每题有且仅有一个正确选项&#xff09; 6.对表达式a(b-c)*d的前缀表达式为( ),其中 、- 、 * 是运算符。 A. * a - bcd B. a * - …

【从0实现React18】 (四) 如何触发更新 带你了解react触发更新的流程以及更新后如何触发render

常见的触发更新的方式 创建 React 应用的根对象 ReactDOM.creatRoot().render()&#xff1b;类组件 this.setState()&#xff1b;函数组件 useState useEffect&#xff1b; 我们希望实现一套统一的更新机制&#xff0c;他的特点是&#xff1a; 兼容上述触发更新的方式方便后续…

c++学习-----内存管理

1. C/C内存分布 我们先来看下面的一段代码和相关问题 答案揭晓&#xff1a; 这里很多人会误认为*char2在常量区&#xff0c;这其实是错误的 因为&#xff1a; 首先在内存字符常量区分配一块内存空间放下”abcd\0”&#xff0c;然后在栈中分配一块连续的内存空间&#xff0c;…

SQL-Python

师从黑马程序员 数据库介绍 数据库就是存储数据的库 数据组织&#xff1a;库->表->数据 数据库和SQL的关系 MySQL的基础命令 SQL基础 SQL语言的分类 SQL的语法特征 DDL-库管理 show DATABASES;use sys;SELECT database();CREATE DATABASE test CHARSET utf-8;SHOW D…

学习C++第二天

1.缺省参数 缺省参数的概念&#xff1a; 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时&#xff0c;如果没有指定实参则采用该形参的缺省值&#xff0c;否则使用指定的实参。 void show(int a 10) {cout << a << endl; }int main() {sho…

ubuntu18.04 编译HBA 并实例运行

HBA是一个激光点云层级式的全局优化的程序&#xff0c;他的论文题目是&#xff1a;HBA: A Globally Consistent and Efficient Large-Scale LiDAR Mapping Module&#xff0c;对应的github地址是&#xff1a;HKU-Mars-Lab GitHub 学习本博客&#xff0c;可以学到gtsam安装&am…

提升Python技能的七个函数式编程技巧

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 递归📝 结构化模式匹配📝 不变性📝 纯函数📝 高阶函数📝 函数组合📝 惰性求值⚓️ 相关链接 ⚓️📖 介绍 📖 在现代编程中,虽然Python并不是一门纯粹的函数式编程语言,但函数式编程(Funct…

Linux C/C++ socket函数

目录 socket函数 函数原型 头文件 功能 返回值 参数 错误码 socket函数 函数原型 int socket(int domain, int type, int protocol); 头文件 #include <sys/types.h> #include <sys/socket.h> 功能 创建一个用于通信的端点&#xff0c;并返回一个文件描述符…

登录安全分析报告:链家地产

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞 …

力扣刷题 杨辉三角(使用c++ vector解法)

杨辉三角 题目描述示例1示例2提示:代码 题目描述 给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例1 输入: numRows 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]] 示例2 …