对于管道和FIFO来说。必须应该先有读取者存在。否则先有写入者是没有意义的。

而消息队列则不同,它是一个消息链表,有足够写权限的线程可往别的队列中放置消息,有足够读权限的线程可从队列中取走消息。每一个消息都是一个记录,它由发送者赋予一个优先级。在某个进程往一个队列写入消息之前。并不须要另外某个进程在该队列上等待消息的到达。消息队列是随内核的持续性,一个进程能够往某个队列写入一些消息,然后终止,再让另外一个进程在以后的某个时刻读出这些消息。这跟管道和FIFO不一样,当一个管道或FIFO的最后一次关闭时,仍在该管道或FIFO上的数据将丢弃。

队列中的每一个消息都具有例如以下属性:

1、一个无符号整数优先级(Posix)或一个长整数类型(System V)

2、消息的数据部分长度(能够为0)

3、数据本身(假设长度大于0)

链表的头文件里含有当前队列的两个属性:队列中同意的最大消息数以及每一个消息的最大大小。

消息队列的打开、关闭、删除函数

#include <mqueue.h>
mqd_t mq_open(const char *name, int oflag, ..../*mode_t mode, struct mq_attr *attr */) // 返回值:成功返回消息队列描写叙述符,出错返回-1
int mq_close(mqd_t mqdes) // 返回值:成功返回0。失败返回-1
int mq_unlink(const char *name) // 返回值:成功为0,失败-1

调用mq_close函数后。调用进程能够不再使用该描写叙述符,但其消息队列并不从系统中删除。一个进程终止时。它的全部打开着的消息队列都关闭,就像调用了mq_close一样。要删除消息队列,必须调用mq_unlink函数。事实上。每一个消息队列都有一个记录打开着描写叙述符数的引用计数器,因而:当一个消息队列的引用计数仍大于0时。其name就能删除,但该队列的析构要到最后一个mq_close发生时才进行。Posix消息队列具有随内核的持续性,即使当前没有进城打开着某个消息队列,该队列及其上的各个消息也将一直存在,直到调用mq_unlink并让它的引用计数达到0以删除该队列为止。

创建消息队列:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <mqueue.h>
#include <sys/stat.h> #define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) int
Getopt(int argc, char *const *argv, const char *str)
{
int opt;
if((opt = getopt(argc, argv, str)) == '? ')
exit(1);
return (opt);
} int
main(int argc, char **argv)
{
int c, flags;
mqd_t mqd; flags = O_RDWR | O_CREAT;
while((c = Getopt(argc, argv, "e")) != -1){
switch(c){
case 'e':
flags |= O_EXCL;
break;
}
}
if(optind != argc -1){
printf("usage:mqcreate [-e] <name>.\n");
return -1;
}
mqd = mq_open(argv[optind], flags, FILE_MODE, NULL); mq_close(mqd);
exit(0);
}

注意此处的编译所用命令要加上链接选项"-lrt":gcc -lrt mqcreate1.c -o mqcreate1

存在的一个疑问:运行可运行文件后,我也不知道所创建的消息队列跑哪去了……

从系统中删除一个消息队列。

#include <mqueue.h>
#include <stdlib.h>
#include <stdio.h> int
main(int argc, char **argv)
{
if(argc != 2){
printf("usage:mqunlink <name>.\n");
return 0;
} if(mq_unlink(argv[1])){
printf("unlink mq error.\n");
return -1;
}
exit(0);
}

消息队列的属性函数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 *attr, struct mq_attr *oattr); // 返回值:成功为0,出错为-1

每一个消息队列都有一些属性,mq_getattr返回这些属性,mq_setattr则设置当中的某个属性,这些属性包括在结构体mq_attr里:

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_attr结构的指针可作为mq_open的第四个參数传递,从而同意在创建新队列时。指定mq_maxmsg和mq_msgsize属性。

mq_open忽略该结构的另外两个成员。
mq_getattr把所指定队列的当前属性填入由attr指向的结构。mq_setattr给所指定队列设置属性,但仅仅使用attr指向的mq_attr结构的mq_flags成员,以设置或清除非堵塞标志。该结构的其它三个成员被忽略:每一个队列的最大消息数和每一个消息的最大字节数仅仅能在创建队列时设置,队列中的当前消息数则仅仅能获取而不能设置。

mqgetattr.c程序

#include <unistd.h>
#include <mqueue.h> int
main(int argc, char **argv)
{
mqd_t mqd;
struct mq_attr attr; if(argc != 2){
printf("usage:mqgetattr <name>.\n");
return -1;
} mqd = mq_open(argv[1], O_RDONLY); mq_getattr(mqd, &attr);
printf("max #msgs = %ld, max #bytes/msg = %ld,"
"#currently on queue = %ld\n",
attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs);
mq_close(mqd);
exit(0);
}

创建消息队列时指定创建队列的最大消息数和每一个消息的最大大小程序例如以下:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <mqueue.h>
#include <sys/stat.h> #define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
struct mq_attr attr; /*mq_maxmsg and mq_msgsize both init to 0*/ int
Getopt(int argc, char *const *argv, const char *str)
{
int opt;
if((opt = getopt(argc, argv, str)) == '?')
exit(1);
return (opt);
} int
main(int argc, char **argv)
{
int c, flags;
mqd_t mqd; flags = O_RDWR | O_CREAT;
while((c = Getopt(argc, argv, "e")) != -1){
switch(c){
case 'e':
flags |= O_EXCL;
break;
case 'm':
attr.mq_maxmsg = atol(optarg);
break;
case 'z';
attr.mq_msgsize = atol(optarg);
break;
}
}
if(optind != argc -1){
printf("usage:mqcreate [-e] <name>.\n");
return -1;
}
if((attr.mq_maxmsg != 0 && attr.mq_msgsize == 0) ||
attr.mq_maxmsg == 0 && attr.mq_msgsize != 0){
printf("must specify both -m maxmsg and -z msgsize");
return -1;
}
mqd = mq_open(argv[optind], flags, FILE_MODE,
(attr.mq_maxmsg != 0)? &attr:NULL); mq_close(mqd);
exit(0);
}

mq_send和mq_receive函数分别用于往一个队列中放置一个消息和从一个队列中取走一个消息。

每一个消息有一个优先级。它是一个小于MQ_PRIO_MAX的无符号整数。

mq_receive总是返回所指定队列中最高优先级的最早小子,并且该优先级能随消息的内容及其长度一同返回。

#include <mqueue.h>
int mq_send(mqd_t mqdes, const char ptr, size_t len, unisgned int prio); //返回值:成功返回0。出错-1
ssize_t mq_receive(mqd_t mqdes, char *ptr, size_t len, unsigned int *priop); //返回值:成功返回0,出错-1

mq_receive的len參数的值不能小于能加到所指定队列中的消息的最大大小(该队列mq_attr结构的mq_msgsize成员)。要是len小于该值。mq_receive理解返回EMSGSIZE错误。

mq_send的prio參数是待发送消息的优先级,其必须小于MQ_PRIO_MAX。

假设mq_receive的priop參数是一个非空指针,所返回消息的优先级就通过该指针存放。

mqsend.c程序:

#include <unistd.h>
#include <mqueue.h>
#include <stdlib.h>
#include <stdio.h> int
main(int argc, char **argv)
{
mqd_t mqd;
void *ptr;
size_t len;
uint_t prio; if(argc != 4){
printf("usage:mqsen <name> <#bytes> <priority>.\n");
return -1;
}
len = atoi(argv[2]);
prio = atoi(argv[3]); mqd = mq_open(argv[1], O_WRONLY);
mq_send(mqd, ptr, len, prio);
exit(0);
}
#include <unistd.h>
#include <mqueue.h>
#include <stdlib.h>
#include <stdio.h> int
main(int argc, char **argv)
{
int c, flags;
mqd_t mqd;
ssize_t n;
uint_t prio;
void *buff;
struct mq_attr attr; flags = O_RDONLY;
while((c = getopt(argc, argv, "n")) != -1){
switch(c){
case 'n';
flags |= O_NONBLOCK;
break;
}
}
if(optind != argc -1){
printf("usage:mqreceive [-n] <name>.\n");
return -1;
} mqd = mq_open(argv[optind], flags);
mq_getattr(mqd, &attr); buff = malloc(attr.mq_msgsize); n = mq_receive(mqd, buff, attr.mq_msgsize, &prio);
printf("read %ld bytes, priotiry = %u\n", (long)n, prio);
exit(0);
}

消息队列的限制:

1、创建消息队列时的队列中的最大消息数限制mq_mqxmsg、给定消息的最大字节数mq_msgsize

2、一个进程能够同一时候拥有的打开消息队列的最大数目MQ_OPEN_MAX、随意消息的最大优先级值MQ_PRIO_MAX加1(通过调用sysconf函数获取)

mqsysconf.c

#include <mqueue.h>
#include <unistd.h>
#include <stdio.h> int
main(int argc, char **argv)
{
printf("MQ_OPEN_MAX = %ld, MQ_PRIO_MAX = %ld\n",
sysconf(_SC_MQ_OPEN_MAX), sysconf(_SC_MQ_PRIO_MAX));
return 0;
}

參考:《UNP2》

Linux环境编程之IPC进程间通信(五):Posix消息队列1的更多相关文章

  1. Linux 进程间通信(posix消息队列 简单)实例

    Linux 进程间通信(posix消息队列 简单)实例 详情见: http://www.linuxidc.com/Linux/2011-10/44828.htm 编译: gcc -o consumer ...

  2. Linux IPC实践(7) --Posix消息队列

    1. 创建/获取一个消息队列 #include <fcntl.h> /* For O_* constants */ #include <sys/stat.h> /* For m ...

  3. linux网络编程之socket编程(五)

    今天继续学习socket网络编程,最近北京阴雨连绵,降温明显,感觉是要立马转入冬季的节奏,天冷晚上得注意多盖点被子哦,言归正传,进入正题: 对于之前写的回射客户/服务器端的程序中,我们是用的read和 ...

  4. Linux进程间通信(IPC)编程实践(十二)Posix消息队列--基本API的使用

    posix消息队列与system v消息队列的区别: (1)对posix消息队列的读总是返回最高优先级的最早消息,对system v消息队列的读则能够返回随意指定优先级的消息. (2)当往一个空队列放 ...

  5. linux网络编程之posix消息队列

    在前面已经学习了System v相关的IPC,今天起学习posix相关的IPC,关于这两者的内容区别,简单回顾一下: 而今天先学习posix的消息队列,下面开始: 接下来则编写程序来创建一个posix ...

  6. linux网络编程之posix信号量与互斥锁

    继上次学习了posix线程之后,这次来讨论一下posix信号量与互斥锁相关的知识: 跟posix消息队列,共享内存的打开,关闭,删除操作一样,不过,上面的函数是对有名信号量进行操作,通过man帮助可以 ...

  7. Linux环境进程间通信(三):消息队列

    linux下进程间通信的几种主要手段: 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允 ...

  8. (转)Linux环境进程间通信----系统 V 消息队列列

    转:http://www.ibm.com/developerworks/cn/linux/l-ipc/part3/ 消息队列(也叫做报文队列)能够克服早期unix通信机制的一些缺点.作为早期unix通 ...

  9. Linux进程间通信IPC学习笔记之消息队列(SVR4)

    Linux进程间通信IPC学习笔记之消息队列(SVR4)

随机推荐

  1. win10下设置IIS、安装php7.2

    开启IIS及相关功能: 控制面板——程序和功能——启用或关闭Windows功能——勾选Internet Information Service——万维网服务——性能和功能——勾选CGI 开启成功后在 ...

  2. [javaSE] 数据结构(二叉树-遍历与查找)

    前序遍历:中,左,右 中序遍历:左,中,右 后序遍历:左,右,中 二叉树查找 从根节点进行比较,目标比根节点小,指针移动到左边 从根节点进行比较,目标比根节点大,指针移动到右边 /** * 前序遍历 ...

  3. zoj 3747 (DP)(连续至多,连续至少)

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5170 参考: http://blog.csdn.net/cc_again/ar ...

  4. 使用jQuery的validation插件实现表单校验

    前端表单校验: <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...

  5. JDBC入门(1)—— 入门案例

    JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组 ...

  6. C#与.NET的区别和C#程序结构

    C#语言及其特点 (1)语法简洁,不允许直接操作做内存,去掉指针操作 (2)彻底的面向对象设计,C#具有面向对象所应用的一切特性:封装.继承.多态 (3)与Web紧密结合,C#支持绝大多数的Web标准 ...

  7. 13 Reasons Why You Should Pay Attention to Mobile Web Performance

    Mobile is no longer on the sidelines. If you’re not already thinking mobile first, you should at lea ...

  8. window.event.srcElement与window.event.target 触发事件的元素 触发事件对象的获取,window.event与时间函数参数的event是同一个 事件对象

    判断事件触发的元素:     var tag = window.event.target || window.event.srcElement;    if (tag.tagName.toLowerC ...

  9. line-height属性的深入了解

    line-height属性的细节与大多数CSS属性不同,line-height支持属性值设置为无单位的数字.有无单位在子元素继承属性时有微妙的不同. 语法line-height: normal | & ...

  10. MongoDB Limit/限制记录

    Limit() 方法 要限制 MongoDB 中的记录,需要使用 limit() 方法. limit() 方法接受一个数字型的参数,这是要显示的文档数. 语法: limit() 方法的基本语法如下 & ...