第三十四章 POSIX消息队列
POSIX消息队列相关函数
mq_open
功能:
用来创建和访问一个消息队列
原型:
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 : 某个消息队列的名字
1. 必须以/开头,并且后续不能有其它/,形如/somename
2. 长度不能超过NAME_MAX
oflag : 与open函数类似,可以是O_RDONLY、O_WRONLY、O_RDWR、O_CREAT、O_EXCL、O_NONBLOCK等
mode :如果oflag指定了O_CREAT,需要设置mode
attr : 指定消息队列的属性
Link with -lrt.
返回值:
成功 : 返回消息队列文件描述符
失败 : -1
mq_close
功能:
关闭消息队列(并不代表删除一个消息队列,仅仅只是关闭了消息队列描述符,不能再通过描述符去访问消息队列)
原型:
mqd_t mq_close(mqd_t mqdes);
参数:
mqdes : 消息队列描述符
返回值:
成功 : 0
失败 : -1
mq_unlink
功能:
删除消息队列(删除一个连接数,当连接数为0的时候,才真正将文件删除)
原型:
mqd_t mq_unlink(const char* name);
参数:
name : 消息队列名字
返回值:
成功 : 0
失败 : -1
mq_getattr|mq_setattr
功能:
获取、设置消息队列属性
原型:
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);
参数:
mqdes : 消息队列的描述字
attr :获取消息队列的属性放到这个结构体中
newattr : 需要设置的新属性
oldattr : 返回原来的属性
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 */
};
返回值:
成功 : 0
失败 : -1
Link with -lrt.
mq_send
功能:
发送消息
原型:
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
mq_receive
功能:
接收消息
原型:
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
注意:
返回指定消息队列中最高优先级的最早消息
mq_notify
功能:
建立或者删除消息到达通知事件(system V没有这个能力,也就是消息队列从空到有消息这样的事件会被通知到某个进程,只要这个进程注册了这种通知事件,就可以被通知)
原型:
int mq_notify(mqd_t mqdes, const struct sigevent *sevp);
参数:
mqdes : 消息队列的描述字
sevp
非空表示当消息到达且消息队列先前为空,那么将得到通知
NULL表示撤销已注册的通知事件
union sigval { /* Data passed with notification */
int sival_int; /* Integer value */
void *sival_ptr; /* Pointer value */
};
struct sigevent {
int sigev_notify; /* Notification method */
int sigev_signo; /* Notification signal */
union sigval sigev_value; /* Data passed with notification */
void (*sigev_notify_function) (union sigval); /* Function used for thread notification (SIGEV_THREAD) */
void *sigev_notify_attributes; /* Attributes for notification thread (SIGEV_THREAD) */
pid_t sigev_notify_thread_id; /* ID of thread to signal (SIGEV_THREAD_ID) */
};
返回值:
成功 : 0
失败 : -1
通知方式:
产生一个信号
创建一个线程执行一个指定的函数
注意:
任何时刻只能有一个进程可以被注册为接收某个给定队列的通知
当有一个消息到达某个先前为空的队列,而且已有一个进程被注册为接收该队列的通知时,只有没有任何线程阻塞在该队列的mq_receive调用的前提下,通知才会发出
当通知被发送给它的注册进程时,其注册被撤销。进程必须再次调用mq_nitify以重新注册(如果需要的话),重新注册要放在从消息队列读出消息之前而不是之后
Link with -lrt
POSIX消息队列示例
mq_open.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#include <mqueue.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0)
int main(int argc, char const *argv[])
{
mqd_t mqid;
mqid = mq_open("/abc", O_CREAT|O_RDWR, 0666, NULL);
if(mqid == (mqd_t)-1)
ERR_EXIT("mq_open");
printf("\n");
mq_close(mqid);
return 0;
}
对于SYSTEM IPC可以使用ipcs查看;对于POSIX IPC,当我们创建一个消息队列后,实际上在系统中已经存在了,存在于一个虚拟的文件系统中,但是这个虚拟的文件系统我们需要挂载到一个目录下才能使用·
man 7 mq_overview
# mkdir /dev/mqueue
# mount -t mqueue none /dev/mqueue
getattr.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#include <mqueue.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0)
int main(int argc, char const *argv[])
{
mqd_t mqid;
mqid = mq_open("/abc", O_RDONLY);
if(mqid == (mqd_t)-1)
ERR_EXIT("mq_open");
printf("\n");
struct mq_attr mqstat;
int ret = mq_getattr(mqid, &mqstat);
if(ret == -1)
ERR_EXIT("mq_getattr");
printf("Flags : %ld\n",mqstat.mq_flags);
printf("mq_maxmsg : %ld\n",mqstat.mq_maxmsg);
printf("mq_msgsize : %ld\n",mqstat.mq_msgsize);
printf("mq_curmsgs : %ld\n",mqstat.mq_curmsgs);
mq_close(mqid);
return 0;
}
mq_snd.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#include <mqueue.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0)
typedef struct str{
char name[32];
int age;
}STU;
int main(int argc, char *argv[])
{
if(argc != 2)
{
fprintf(stderr, "Useage %s prio\n", argv[1]);
exit(EXIT_FAILURE);
}
mqd_t mqid;
mqid = mq_open("/abc", O_WRONLY);
if(mqid == (mqd_t)-1)
ERR_EXIT("mq_open");
printf("mq_open success\n");
STU stu;
strcpy(stu.name, "test");
stu.age = 20;
unsigned prio = atoi(argv[1]);
int ret = mq_send(mqid, (const char*)&stu, sizeof(STU), prio);
if(ret == -1)
ERR_EXIT("mq_send");
mq_close(mqid);
return 0;
}
m_rcv.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#include <mqueue.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0)
typedef struct str{
char name[32];
int age;
}STU;
int main(int argc, char *argv[])
{
mqd_t mqid;
mqid = mq_open("/abc", O_RDONLY);
if(mqid == (mqd_t)-1)
ERR_EXIT("mq_open");
printf("mq_open success\n");
STU stu;
memset((void*)&stu, 0, sizeof(STU));
unsigned prio;
struct mq_attr mqstat;
int ret = mq_getattr(mqid, &mqstat);
if(ret == -1)
ERR_EXIT("mq_getattr");
// Message too long
//int ret = mq_receive(mqid, (char*)&stu, sizeof(STU), &prio);
ret = mq_receive(mqid, (char*)&stu, mqstat.mq_msgsize, &prio);
if(ret == -1)
ERR_EXIT("mq_receive");
printf("name : %s\n",stu.name);
printf("age : %d\n",stu.age);
printf("prio : %u\n",prio);
mq_close(mqid);
return 0;
}
获取消息时的优先级
./mq_snd 2
./mq_snd 1
./mq_snd 0
./mq_rcv
name : test
age : 20
prio : 2
./mq_rcv
name : test
age : 20
prio : 1
./mq_rcv
name : test
age : 20
prio : 0
./mq_snd 0
./mq_snd 1
./mq_snd 2
./mq_rcv
name : test
age : 20
prio : 2
./mq_rcv
name : test
age : 20
prio : 1
./mq_rcv
name : test
age : 20
prio : 0
mq_notify.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#include <mqueue.h>
#include <signal.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0)
typedef struct str{
char name[32];
int age;
}STU;
mqd_t mqid;
size_t size;
struct sigevent sigev;
void handler_user1(int sig)
{
mq_notify(mqid, &sigev);
STU stu;
memset((void*)&stu, 0, sizeof(STU));
unsigned prio;
int ret = mq_receive(mqid, (char*)&stu, size, &prio);
if(ret == -1)
ERR_EXIT("mq_receive");
printf("name : %s\n",stu.name);
printf("age : %d\n",stu.age);
printf("prio : %u\n",prio);
}
int main(int argc, char const *argv[])
{
mqid = mq_open("/abc", O_RDONLY);
if(mqid == (mqd_t)-1)
ERR_EXIT("mq_open");
struct mq_attr mqstat;
int ret = mq_getattr(mqid, &mqstat);
if(ret == -1)
ERR_EXIT("mq_getattr");
size = mqstat.mq_msgsize;
signal(SIGUSR1, handler_user1);
//通知方式
sigev.sigev_notify = SIGEV_SIGNAL;
//通知信号
sigev.sigev_signo = SIGUSR1;
mq_notify(mqid, &sigev);
for(;;)
pause();
mq_close(mqid);
return 0;
}
mq_unlink.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#include <mqueue.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0)
int main(int argc, char const *argv[])
{
mq_unlink("/abc");
return 0;
}
cat /dev/mqueue/abc
QSIZE:0 NOTIFY:0 SIGNO:10 NOTIFY_PID:5139
NOTIFY : 通知方式
SIGNO : 当前用那个信号来通知
NOTIFY_PID : 这种通知会发送给那个进程
第三十四章 POSIX消息队列的更多相关文章
- (十四)RabbitMQ消息队列-启用SSL安全通讯
原文:(十四)RabbitMQ消息队列-启用SSL安全通讯 如果RabbitMQ服务在内网中,只有内网的应用连接,我们认为这些连接都是安全的,但是个别情况我们需要让RabbitMQ对外提供服务.这种情 ...
- Gradle 1.12用户指南翻译——第三十四章. JaCoCo 插件
本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
- “全栈2019”Java多线程第三十四章:超时自动唤醒被等待的线程
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java第三十四章:可变参数列表
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- Linux进程间通信(IPC)编程实践(十二)Posix消息队列--基本API的使用
posix消息队列与system v消息队列的区别: (1)对posix消息队列的读总是返回最高优先级的最早消息,对system v消息队列的读则能够返回随意指定优先级的消息. (2)当往一个空队列放 ...
- 第5章 Posix 消息队列
5.1 概述 消息队列可以认为是一个链表.有写权限的线程可往消息队列中放置消息,有读权限的线程可以从消息队列中取走消息. 消息队列和管道/FIFO的区别: (1)消息队列往一个队列中写消息前,并不需要 ...
- 第三十五章 POSIX共享内存
POSIX共享内存函数介绍 shm_open 功能: 用来创建或打开一个共享内存对象 原型: int shm_open(const char *name, int oflag, mode_t mode ...
- 第三十四章 metrics(2)- 搭建metrics平台
一.基本架构图 1.整个架构组件: java客户端 dropwizard-metrics:springboot.hystrix的metric体层使用了这个,所以我们需要自己封装向statsd发包的方法 ...
- 我的学习之路_第三十四章_jsp
jsp 在只有servlet时,输出页面内容比较麻烦(成本高,java代码中输出HTML标签),所以需要一种技术,主要是HTML页面的代码(HTML,css,js),可以嵌入java代码,来实现动态页 ...
随机推荐
- ELK 学习笔记之 Logstash之output配置
Logstash之output配置: 输出到file 配置conf: input{ file{ path => "/usr/local/logstash-5.6.1/bin/spark ...
- php有关数据推荐
# PHP<PHP程序设计>(第2版) --PHP语法和入门最好的书<PHP5权威编程> --PHP入门后升级书<深入PHP:面向对象.模式与实践>(第3版) ...
- 低效sql语句执行缓慢引起的大量占用服务器的CPU问题处理 (优化心得)
1> 2> 3> 4> 5>删除不良的执行计划后执行时间仍然有150s,这实在是太慢了,继续查看原sql代码,发现父表的关联条件放在了子查询里,这是应该避免的 调整原sq ...
- java之ReentrantLock详解
前言 如果一个代码块被synchronized修饰了,当一个线程获取了相应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的释放,现在有这么一种情况,这个获取锁的线程由于要等待IO或者其他原 ...
- LeetCode初级算法--数组01:只出现一次的数字
LeetCode初级算法--数组01:只出现一次的数字 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn. ...
- Java工程师学习指南(完结篇)
Java工程师学习指南 完结篇 先声明一点,文章里面不会详细到每一步怎么操作,只会提供大致的思路和方向,给大家以启发,如果真的要一步一步指导操作的话,那至少需要一本书的厚度啦. 因为笔者还只是一名在校 ...
- abp(net core)+easyui+efcore实现仓储管理系统——EasyUI之货物管理五 (二十三)
abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+ ...
- webapck 按需加载及版本控制问题
在启用webpack的懒加载(按需加载)后,我们会遇到要解决缓存的问题. 解决缓存问题有几种方法: 第一种就是加个hash值.便每次修改后所编译后的文件名都不一样.这样能达到预期解决缓存的效果.具体设 ...
- maven子项目导出成jar包及运行
第一步:选这idea右侧栏的maven projects 第二步:选中需要打包成jar包的项目下的lifecycle 第三步:选中package 第四步:点击开始导出 第五步:使用winRAR打开ja ...
- 事业单位招聘网搭建思路和seo方法
期望目标 自动采集事业单位招聘信息+自动发布到网站+自动提交网址到百度+自动发外链. 技术框架 前端用layUI,后端用flask,数据库用的elasticsearch,编程语言用Python 3.7 ...