POSIX 消息队列 和 系列函数
一、在前面介绍了system v 消息队列的相关知识,现在来稍微看看posix 消息队列。
posix消息队列的一个可能实现如下图:
其实消息队列就是一个可以让进程间交换数据的场所,而两个标准的消息队列最大的不同可能只是api
函数的不同,如system v 的系列函数是msgxxx,而posix 是mq_xxx。posix 消息队列也有一些对消息长度等的限制,man
7 mq_overview:
simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ cat /proc/sys/fs/mqueue/msg_max
10
simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ cat /proc/sys/fs/mqueue/msgsize_max
8192
simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ cat /proc/sys/fs/mqueue/queues_max
256
即一个消息队列最多能有10条消息,每条消息的最大长度为8192字节,一个系统最多能有256个消息队列。
还有一点是,在Linux上,posix 消息队列是以虚拟文件系统实现的,必须将其挂载到某个目录才能看见,如
# mkdir /dev/mqueue
# mount -t mqueue none /dev/mqueue
通过cat 命令查看消息队列的状态,假设mymq 是创建的一条消息队列的名字
$ cat /dev/mqueue/mymq
QSIZE:129 NOTIFY:2 SIGNO:0 NOTIFY_PID:8260
QSIZE:消息队列所有消息的数据长度
NOTIFY_PID:某个进程使用mq_notify 注册了消息到达异步通知事件,即此进程的pid
NOTIFY:通知方式: 0 is SIGEV_SIGNAL; 1 is SIGEV_NONE; and 2 is SIGEV_THREAD.
SIGNO:当以信号方式通知的时候,表示信号的编号.
二、系列函数,编译时候加上 -lrt 选项,即连接librt 库 (实时库)
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#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: 某个消息队列的名字,必须以/打头,并且后续不能有其它/ ,形如/somename长度不能超过NAME_MAX(255)
oflag:与open函数类似,可以是O_RDONLY、O_WRONLY、O_RDWR,还可以按位或上O_CREAT、O_EXCL、O_NONBLOCK;
mode:如果oflag指定了O_CREAT,需要设置mode。
返回值:成功返回消息队列文件描述符;失败返回-1
功能:关闭消息队列
原型
mqd_t mq_close(mqd_t mqdes);
参数
mqdes : 消息队列描述符
返回值:成功返回0;失败返回-1
功能:删除消息队列
原型
mqd_t mq_unlink(const char *name);
参数
name: 消息队列的名字
返回值:成功返回0;失败返回-1
功能:获取/设置消息队列属性
原型
mqd_t mq_getattr(mqd_t mqdes, struct mq_attr *attr);
mqd_t mq_setattr(mqd_t mqdes, struct mq_attr *newattr, struct mq_attr *oldattr);
返回值:成功返回0;失败返回-1
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_flags 是标志;mq_maxmsg 即一个消息队列消息个数上限;mq_msgsize即一条消息的数据上限;mq_curmsgs即当前消息个数
功能:发送消息
原型
mqd_t mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio);
参数
mqdes:消息队列描述符
msg_ptr:指向消息的指针
msg_len:消息长度
msg_prio:消息优先级
返回值:成功返回0;失败返回-1
功能:接收消息
原型
ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio);
参数
mqdes:消息队列描述符
msg_ptr:返回接收到的消息
msg_len:消息长度,一般需要指定为msgsize_max
msg_prio:返回接收到的消息优先级
返回值:成功返回接收到的消息字节数;失败返回-1
注意:返回指定消息队列中最高优先级的最早消息,优先级最低为0
功能:建立或者删除消息到达通知事件
原型
mqd_t mq_notify(mqd_t mqdes, const struct sigevent *notification);
参数
mqdes:消息队列描述符
notification:
非空表示当消息到达且消息队列先前为空,那么将得到通知;
NULL表示撤消已注册的通知
返回值:成功返回0;失败返回-1
通知方式:
产生一个信号
创建一个线程执行一个指定的函数
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 for thread notification */
void *sigev_notify_attributes;
/* Thread function attributes */
};
sigev_notify 的取值有3个:
SIGEV_NONE:消息到达不会发出通知
SIGEV_SIGNAL:以信号方式发送通知,当设置此选项时,sigev_signo 设置信号的编号,且只有当信号为实时信号时才可以通过sigev_value顺带数据,参考这里。
SIGEV_THREAD:以线程方式通知,当设置此选项时,sigev_notify_function 即一个函数指针,sigev_notify_attributes 即线程的属性
mq_notify 函数注意点:
1、任何时刻只能有一个进程可以被注册为接收某个给定队列的通知
2、当有一个消息到达某个先前为空的队列,而且已有一个进程被注册为接收该队列的通知时,只有在没有任何线程阻塞在该队列的mq_receive调用的前提下,通知才会发出。
3、当通知被发送给它的注册进程时,其注册被撤消。进程必须再次调用mq_notify以重新注册(如果需要的话),重新注册要放在从消息队列读出消息之前而不是之后。
下面写两个小程序测试一下:
mq_send.c
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#include<stdio.h>
#include<stdlib.h> #include<sys/ipc.h> #include<sys/msg.h> #include<sys/types.h> #include<unistd.h> #include<errno.h> #include<mqueue.h> #include<fcntl.h> #include<sys/stat.h> #include<string.h> #define ERR_EXIT(m) \ typedef struct stu int main(int argc, char *argv[]) STU stu; return 0; |
mq_notify.c
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
#include<stdio.h>
#include<stdlib.h> #include<sys/ipc.h> #include<sys/msg.h> #include<sys/types.h> #include<unistd.h> #include<errno.h> #include<mqueue.h> #include<fcntl.h> #include<sys/stat.h> #include<string.h> #include<signal.h> #define ERR_EXIT(m) \ typedef struct stu size_t size; mqd_t mqid; struct sigevent sigev; void handle(int sig) } int main(int argc, char *argv[]) struct mq_attr attr; signal(SIGUSR1, handle); sigev.sigev_notify = SIGEV_SIGNAL; mq_notify(mqid, &sigev); for (; ;) mq_close(mqid); return 0; |
mq_open.c
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#include<stdio.h>
#include<stdlib.h> #include<sys/ipc.h> #include<sys/msg.h> #include<sys/types.h> #include<unistd.h> #include<errno.h> #include<mqueue.h> #include<fcntl.h> #include<sys/stat.h> #define ERR_EXIT(m) \ int main(void) |
先运行./mq_open 用mq_open 创建了一个消息队列并mount 到/dev/mqueue 上,可以查看状态:
simba@ubuntu:/dev/mqueue$ cat /dev/mqueue/abc
QSIZE:0 NOTIFY:0 SIGNO:0 NOTIFY_PID:0
接着运行./mq_notify 再查看状态:
simba@ubuntu:/dev/mqueue$ cat /dev/mqueue/abc
QSIZE:0 NOTIFY:0 SIGNO:10 NOTIFY_PID:3572
准备通知的信号是10号,即SIGUSR1,等待的进程pid即./mq_notify ,此时./mq_notify 进程是阻塞的,正在等待其他进程往消息队列写入消息,现在运行./mq_send
simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./mq_send
Usage: ./mq_send <prio>
simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./mq_send 1
mq_open succ
simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./mq_send 1
mq_open succ
simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$
回头看./mq_notify 的输出:
simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./mq_notify
mq_open succ
name=test, age=20, prio=1
name=test, age=20, prio=1
...........................................
即./mq_send
发送的两条消息都接收到了,需要注意的是虽然通知是一次性的,但我们在消息处理函数再次注册了通知,故能多次接收到通知,但通知只发生在消息队列由空到不空的时候,如果先运行./mq_send
先往消息队列发送了n条消息,那么执行./mq_notify 是不会接收到通知的,一直阻塞着。
POSIX 消息队列 和 系列函数的更多相关文章
- 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.消息队列 消息队列可以认为是一个消息链表,消息队列是随内核持续的.队列中 ...
- 第5章 Posix 消息队列
5.1 概述 消息队列可以认为是一个链表.有写权限的线程可往消息队列中放置消息,有读权限的线程可以从消息队列中取走消息. 消息队列和管道/FIFO的区别: (1)消息队列往一个队列中写消息前,并不需要 ...
- posix 消息队列
注意 在涉及到posix消息的函数时, gcc 编译时要加-lrt参数, 如 gcc -lrt unpipc.c mqpack.c send.c -o send gcc -lrt unpipc.c m ...
- Posix消息队列实现机制
本文是对<Unix 网络编程 卷2:进程通信>的笔记. 引言 消息队列是进程间通信的一种方式,可是如果不理解他的实现原理,会有众多不理解之处,下面就结合本书中的例子,对posix消息队列来 ...
- Linux IPC实践(7) --Posix消息队列
1. 创建/获取一个消息队列 #include <fcntl.h> /* For O_* constants */ #include <sys/stat.h> /* For m ...
- 进程间通信--POSIX消息队列
相关函数: mqd_t mq_open(const char *name, int oflag); mqd_t mq_send(mqd_t mqdes, const char *msg_ptr, si ...
- POSIX 消息队列 之 概述 链接方式
NAMEmq_overview —— POSIX消息队列概述 DESCRIPTIONPOSIX消息队列允许进程以消息的形式交换数据.此API与System V消息队列(msgget(2),msgsnd ...
- POSIX 消息队列 之 参数说明
消息队列 一.函数 mq_open 头文件 mqueue.h: 原型 mqd_t mq_open(const char *name, int oflag, .../*mode_t mode,struc ...
随机推荐
- iOS开发-iPad侧边栏Tab选项卡切换
Android中习惯了叫侧边栏,iOS中如果不习惯侧边栏称呼的话可以叫dock,侧边栏的切换,类似于Android中的底部导航栏的切换,iPad尺寸大了一些,导航的栏目放在侧边会显示的更好耐看一些.选 ...
- CSS深入了解border:利用border画三角形等图形
三角形实际上是border的产物 我们正常使用的border都是四边一个颜色,当我们把四边换上不同颜色 那么你就会发现,三角来了~! <!DOCTYPE html> <html la ...
- Android -- PullToRefresh应用
PullToRefresh 支持ListView.ExpandableListView.GridView.WebView 下载地址:https://github.com/chrisbanes/Andr ...
- IIS6.0支持PHP设置
找到了一份兼职,做网站的,但是公司里面服务器是用的IIS,Win2003系统,而且以前的网站都是aspx的.老板是我们学校的一个老师,我是被学长推荐过去了. --------------------- ...
- Sqlserver存储过程生成日期维度
话不多说,之前已经有一篇日志是利用oracle的存储过程生成日期维度表,接下来我们就用sqlserver来实现这个操作,如下面的步骤所示 1:创建日期维度表(Dim_time) USE [DW] GO ...
- (转)深入浅出K-Means算法
原文地址:http://www.csdn.net/article/2012-07-03/2807073-k-means 摘要:在数据挖掘中,K-Means算法是一种 cluster analysis ...
- 在Fedora8上安装使用ActiveMQ5.8
[ActiveMQ安装] ActiveMQ在win平台的安装简单,在Linux Fedora上安装也不难,解压就可以了.以下是我总结的步骤: 第一步,从以下地址下载apache-activemq-5. ...
- TotalCommander如何比较文件夹并提取出重复的文件
1 如图所示,我左侧有一万本多小说,右侧有两千五百多本小说,我希望比较这两个文件夹相同的小说并剪切到一个新的文件夹中. 2 我们使用Total Commander对比这两个文件夹 3 随后两个文件夹相 ...
- 如何用7-zip创建自解压文件,7Z软件如何使用
1 要创建自解压文件,一般都是双击直接解压到C盘的Program Files文件夹里面,或许还需要在桌面创建一个快捷方式之类的.但是一般的绿色软件除了复制到Program Files还需要运行一下绿化 ...
- Appium Python 五:元素定位
总结 单个元素定位: driver.find_element_by_accessibility_id(id) driver.find_element_by_android_uiautomator(ui ...