进程间通信-POSIX 消息队列
POSIX 消息队列
POSIX 消息队列可以认为是一个消息链表。进程(线程)可以往里写消息,也可以从里面取出消息。可以在不相关的进程之间发送和接收数据。
创建(打开)消息队列-mq_open()函数
mq_open()函数用于打开或创建一个消息队列,该函数定义如下:
#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);
参数说明
- name:消息队列的名称,形式为一个斜杠 "/" 开头的字符串,类似于文件路径。
- oflag:打开标志,用于指定消息队列的打开方式,可以是以下之一或它们的组合:
- O_RDONLY:只读方式打开消息队列。
- O_WRONLY:只写方式打开消息队列。
- O_RDWR:读写方式打开消息队列。
- O_CREAT:如果消息队列不存在,则创建它。
- O_EXCL:与 O_CREAT 同时使用,确保创建一个新的消息队列。
- mode:用于指定创建的消息队列的操作权限。类似于 chmod 命令中的权限设置。
- attr:指向结构体 mq_attr 的指针,指定消息队列的属性,如最大消息数、消息大小等。
返回值
- 如果函数执行成功,返回一个非负整数,表示消息队列的标识符(文件描述符)。
- 如果发生错误,返回 -1。可以通过 errno 变量来获取具体的错误信息。
注意事项
- 消息队列的名称在系统中必须是唯一的,不同进程可以通过相同名称打开同一个消息队列。
- 消息队列的名称需要以斜杠 "/" 开头,必须符合路径名规则(最多由PATH_MAX个字节构成,包括结尾的空字节)。
- 创建的消息队列以文件形式保存在 /dev/mqueque 目录下。
用法
1 #include<stdio.h>
2 #include<fcntl.h>
3 #include<mqueue.h>
4 #include<sys/stat.h>
5
6 int main(int argc, char** argv)
7 {
8 mqd_t mqd = mq_open("/myqueue", O_RDONLY | O_CREAT | O_EXCL, 0666, NULL);
9 if(mqd == -1)
10 {
11 perror("mq_open");
12 return -1;
13 }
14
15 return 0;
16 }
如果代码中使用了 POSIX 消息队列相关代码,在编译时,需要指定额外的库文件,例如:
gcc my_mqueue.c -o a.out -lrt
输出:
$ ./a.out
$ ls -l /dev/mqueue/
总用量 0
-rw-rw-r-- 1 test test 80 12月 21 10:04 myqueue
关闭消息队列-mq_close()函数
mq_close()函数用于关闭一个已经打开的消息队列描述符,该函数定义如下:
#include <mqueue.h> int mq_close(mqd_t mqdes);
参数说明
- mqdes:待关闭的消息队列描述符。
返回值
- 如果函数执行成功,返回0。
- 如果发生错误,返回 -1。可以通过 errno 变量来获取具体的错误信息。
删除消息队列-mq_unlink()函数
mq_unlink()函数用于删除已经存在的消息队列,即删除消息队列的名称。该函数定义如下:
#include <mqueue.h> int mq_unlink(const char *name);
参数说明
- mqdes:要删除的消息队列的名称。
返回值
- 如果函数执行成功,返回0。
- 如果发生错误,返回 -1。可以通过 errno 变量来获取具体的错误信息。
注意事项
- 如果在调用 mq_unlink() 函数之前,没有其他进程打开该消息队列,那么该消息队列将被立即删除,并且所有之前打开的描述符将成为无效。
- 如果有其他进程打开了该消息队列,但没有对该消息队列进行写入或读取操作,那么调用 mq_unlink() 函数后,对该消息队列的访问将立即被阻止,但消息队列本身将保持存在。
- 如果有其他进程当前正在使用该消息队列(执行了读写操作),删除操作将会延迟到所有打开的描述符都关闭或相应进程终止时才会生效。
消息队列的属性
struct mq_attr结构体
struct mq_attr结构体用于描述 POSIX 消息队列属性,包含如下成员:
struct mq_attr {
long mq_flags;
long mq_maxmsg;
long mq_msgsize;
long mq_curmsgs;
};
各个成员的含义如下:
- mq_flags:标志位,取值为0 或者 O_NONBLOCK(非阻塞)
- mq_maxmsg: 是消息队列中允许的最大消息数,默认是10。
- mq_msgsize:消息队列中消息的最大大小,单位是字节,默认是8192字节。
- mq_curmsgs:输出参数,当前队列中的消息数。
查看消息队列默认值:
cat /proc/sys/fs/mqueue/msg_max #查看消息队列的消息最大长度
cat /proc/sys/fs/mqueue/msgsize_max #查看消息队列的消息最大个数
在消息队列的四个属性中:
- mq_curmsgs只能获取不能设置。
- mq_flags只能通过 mq_setattr() 函数设置,该函数的唯一作用就是设置或清除非阻塞标志。
- mq_maxmsg 和 mq_msgsize 只能在创建新队列时由 mq_open() 函数的 attr 参数设置。
- mq_maxmsg 和 mq_msgsize 必须同时指定,否则 mq_open() 函数创建新队列会失败。
- O_NONBLOCK 标识不能通过 mq_flags 指定,可以通过 mq_open() 函数 oflag 参数指定,如果想要移除,通过 mq_setattr() 函数设置。
获取消息队列属性-mq_getattr()函数
mq_getattr()函数用于获取消息队列的属性信息,该函数定义如下:
#include <mqueue.h> int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat);
参数说明
- mqdes:要获取属性的消息队列描述符。
- mqstat:指向 struct mq_attr 结构的指针,用于存储获取的属性信息。
返回值
- 如果函数执行成功,返回0。
- 如果发生错误,返回 -1。可以通过 errno 变量来获取具体的错误信息。
设置消息队列属性-mq_setattr()函数
mq_setattr()函数用于设置消息队列的属性,该函数定义如下:
#include <mqueue.h> int mq_setattr(mqd_t mqdes, const struct mq_attr *mqstat,
struct mq_attr *omqstat);
参数说明
- mqdes:要设置属性的消息队列描述符。
- mqstat:指向 struct mq_attr 结构的指针,指向新的属性信息。
- omqstat:指向 struct mq_attr 结构的指针,保存原先的属性信息。
返回值
- 如果函数执行成功,返回0。
- 如果发生错误,返回 -1。可以通过 errno 变量来获取具体的错误信息。
消息发送与接收
消息发送-mq_send()函数
mq_send() 函数用于向消息队列发送消息,该函数定义如下:
#include <mqueue.h> int mq_send(mqd_t mqdes, const char *msg_ptr,
size_t msg_len, unsigned int msg_prio);
参数说明
- mqdes:消息队列描述符。
- msg_ptr:指向要发送的消息的指针。
- msg_len:要发送的消息的长度,不能超过消息队列的最大长度。
- msg_prio:消息的优先级, 数值越大,优先级越高。优先级低的消息会排在优先级高的消息之后。
返回值
- 如果函数执行成功,返回0。
- 如果发生错误,返回 -1。可以通过 errno 变量来获取具体的错误信息。
- 如果消息队列已满,mq_send() 函数会阻塞直到有空间可用。
- 如果设置了非阻塞标志,此时会立即返回,错误码为 EAGAIN。
消息接收-mq_receive函数
mq_receive() 函数用于从消息队列接收消息。该函数定义如下:
#include <mqueue.h> ssize_t mq_receive(mqd_t mqdes, char *msg_ptr,
size_t msg_len, unsigned int *msg_prio);
参数说明
- mqdes:消息队列描述符。
- msg_ptr:指向接收消息的缓冲区的指针,用于存储接收到的消息。
- msg_len:接收消息的最大长度,必须大于等于消息的实际长度。
- msg_prio:用于存储接收到的消息的优先级。
返回值
- 如果函数执行成功,返回接收到的消息的长度(即实际读取的字节数)。
- 如果发生错误,返回 -1。可以通过 errno 变量来获取具体的错误信息。
- 如果消息队列为空,mq_receive() 函数会阻塞直到有消息可用。
- 如果设置了非阻塞标志,此时会立即返回,错误码为 EAGAIN。
示例
进程A负责读取:
1 #include<stdio.h>
2 #include<sys/stat.h>
3 #include<mqueue.h>
4 #include<fcntl.h>
5 #include<errno.h>
6 #include<unistd.h>
7 #include<stdlib.h>
8
9 int main(int argc, char** argv)
10 {
11 mqd_t mqd = mq_open("/my_mqueue", O_RDONLY);
12 if(mqd == -1)
13 {
14 perror("mq_open");
15 return -1;
16 }
17
18 struct mq_attr attr;
19 if(mq_getattr(mqd, &attr) == -1)
20 {
21 perror("mq_getattr");
22 return -1;
23 }
24
25 char* pBuf = (char*)malloc(attr.mq_msgsize);
26 if(pBuf == NULL)
27 {
28 perror("malloc");
29 return -1;
30 }
31
32 int prio;
33 while(1)
34 {
35 int ret = mq_receive(mqd, pBuf,attr.mq_msgsize, &prio);
36 if(ret == -1)
37 {
38 if(errno == EAGAIN)
39 {
40 printf("no block, contimue to read\n");
41 continue;
42 }
43 perror("mq_receive");
44 return -1;
45 }
46 pBuf[ret] = '\0';
47 printf("read data : %s, prio : %d\n", pBuf, prio);
48 sleep(1);
49 }
50
51 free(pBuf);
52 return 0;
53 }
进程B负责写入:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<unistd.h>
5 #include<sys/stat.h>
6 #include<errno.h>
7 #include<mqueue.h>
8
9 int main(int argc, char** argv)
10 {
11 struct mq_attr attr0;
12 //attr0.mq_flags = O_NONBLOCK; //在此处指定无效
13 attr0.mq_maxmsg = 5;
14 attr0.mq_msgsize = 4096;
15 mqd_t mqd;
16
17 AGAIN:
18 mqd = mq_open("/my_mqueue", O_WRONLY | O_CREAT | O_EXCL /*| O_NONBLOCK*/, 0666, &attr0);
19 if(mqd == -1)
20 {
21 if(errno == EEXIST)
22 {
23 mq_unlink("/my_mqueue");
24 goto AGAIN;
25 }
26 perror("mq_open");
27 return -1;
28 }
29
30 struct mq_attr attr;
31 if(mq_getattr(mqd, &attr) == -1)
32 {
33 perror("mq_getattr");
34 return -1;
35 }
36
37 char* pBuf = (char*)malloc(attr.mq_msgsize);
38 if(pBuf == NULL)
39 {
40 perror("malloc");
41 return -1;
42 }
43
44 /*
45 attr.mq_flags = 0; //取消非阻塞
46 if(mq_setattr(mqd, &attr, NULL) == -1)
47 {
48 perror("mq_setattr");
49 return -1;
50 }
51 */
52 int i = 0;
53 while(1)
54 {
55 sprintf(pBuf, "Data%d", i++);
56 int ret = mq_send(mqd, pBuf, strlen(pBuf) + 1, 10);
57 if(ret == -1)
58 {
59 if(errno == EAGAIN)
60 {
61 printf("no block, continue to write\n");
62 continue;
63 }
64 perror("mq_send");
65 return -1;
66 }
67 printf("send data : %s\n", pBuf);
68 sleep(1);
69 }
70
71 free(pBuf);
72 return 0;
73 }
进程间通信-POSIX 消息队列的更多相关文章
- 进程间通信--POSIX消息队列
相关函数: mqd_t mq_open(const char *name, int oflag); mqd_t mq_send(mqd_t mqdes, const char *msg_ptr, si ...
- Linux 进程间通信(posix消息队列 简单)实例
Linux 进程间通信(posix消息队列 简单)实例 详情见: http://www.linuxidc.com/Linux/2011-10/44828.htm 编译: gcc -o consumer ...
- Linux环境编程之IPC进程间通信(五):Posix消息队列1
对于管道和FIFO来说.必须应该先有读取者存在.否则先有写入者是没有意义的. 而消息队列则不同,它是一个消息链表,有足够写权限的线程可往别的队列中放置消息,有足够读权限的线程可从队列中取走消息.每一个 ...
- Linux进程间通信(IPC)编程实践(十二)Posix消息队列--基本API的使用
posix消息队列与system v消息队列的区别: (1)对posix消息队列的读总是返回最高优先级的最早消息,对system v消息队列的读则能够返回随意指定优先级的消息. (2)当往一个空队列放 ...
- 练习--LINUX进程间通信之消息队列MSG
https://www.ibm.com/developerworks/cn/linux/l-ipc/part3/ 继续坚持,或许不能深刻理解,但至少要保证有印象. ~~~~~~~~~~~~~~ 消息队 ...
- Posix消息队列实现机制
本文是对<Unix 网络编程 卷2:进程通信>的笔记. 引言 消息队列是进程间通信的一种方式,可是如果不理解他的实现原理,会有众多不理解之处,下面就结合本书中的例子,对posix消息队列来 ...
- UNIX IPC: POSIX 消息队列 与 信号
POSIX消息队列可以注册空队列有消息到达时所触发的信号,而信号触发对应的信号处理函数. 下面是一份基本的消息队列和信号处理结合的代码(修改自UNIX网络编程:进程间通信) #include < ...
- [转]Linux进程通信之POSIX消息队列
进程间的消息队列可以用这个实现,学习了下. http://blog.csdn.net/anonymalias/article/details/9799645?utm_source=tuicool&am ...
- Linux IPC POSIX 消息队列
模型: #include<mqueue.h> #include <sys/stat.h> #include <fcntl.h> mq_open() //创建/获取消 ...
- Posix消息队列
转载于:http://blog.csdn.net/zx714311728/article/details/53197196 1.消息队列 消息队列可以认为是一个消息链表,消息队列是随内核持续的.队列中 ...
随机推荐
- 库卡机器人KR240电源模块维修思路讲解
一.库卡机器人KR240电源模块故障诊断 故障诊断是维修过程中的关键步骤.使用库卡提供的诊断工具或软件,对库卡机器人KR240电源模块进行故障诊断.重点关注电源供应.输出电压.电流等关键参数.通过诊断 ...
- php 获取post方法payload(json)形式参数的方法
用默认get方式传递的时候,接收方式没有改变,仍然是$_GET. 但是用post方式传递数据的时候,用$_POST无法接收数据,应为小程序默认post发送的content-type为applicati ...
- docker批量删除容器或镜像
删除容器 停止所有容器 删除所有容器,需要先停止所有运行中的容器 docker stop `docker ps -a -q` docker ps -a -q,意思是列出所有容器(包括未运行的),只显示 ...
- JavaScript的标准库
Object 对象 概述 JavaScript 的所有其他对象都继承自Object对象,即那些对象都是Object的实例. Object对象的原生方法分成两类:Object本身的方法与Object的实 ...
- boot3+JDK17+spring-cloud-gateway:4.0.0+spring-cloud:2022.0.0.0+Nacos2.2.1配置动态路由的网关
项目依赖 配置 # Nacos帮助文档: https://nacos.io/zh-cn/docs/concepts.html # Nacos认证信息 spring.cloud.nacos.config ...
- ASP.NET Core 阿弥陀佛中间件
Amitabha n. <梵>(佛)阿弥陀佛 佛曰: 因果 那么一天 看见文章1. 发现还有2.这么个中间件 于是追寻源码,发现了3. 再然后寻思自己也可以写一个什么中间件,以便学习掌握 ...
- leetcode每日一题:对角线上的质数
题目 2614. 对角线上的质数 给你一个下标从 0 开始的二维整数数组 nums . 返回位于 nums 至少一条 对角线 上的最大 质数 .如果任一对角线上均不存在质数,返回 0 . 注意: 如果 ...
- nodejs读写json文件
读json文件 'use strict'; const fs = require('fs'); let rawdata = fs.readFileSync('student.json'); let s ...
- Win10在WSL上使用Vivado对ZCU 102 PYNQ进行ILA调试
ZCU 102上有两个USB接口(接口信号均为micro-A),其中靠近角落的接口为jtag端口,另外一个是uart端口 vivado自带的硬件管理器通过jtag端口连接到开发板.启动开发板,连接开发 ...
- ApplicationContext 接口的实现类
ClassPathXmlApplicationContext: 它是从类的根路径下加载配置文件 推荐使用这种 FileSystemXmlApplicationContext: 它是从磁盘路径上加载配置 ...