对于管道和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. lodop打印多页

    定义全局变量 var loop = null; 加载时候打印 window.On_CLodop_Opened = function () { print(); //OpenPreview()是调用打印 ...

  2. bnu 10783 格斗游戏 线段与圆的关系

    格斗游戏 Time Limit: 1000ms Memory Limit: 65536KB   64-bit integer IO format: %lld      Java class name: ...

  3. HDU 4747(AC不能)

    http://acm.hdu.edu.cn/showproblem.php?pid=4747

  4. 关于二进制和字符串及base64格式

    字符串转二进制可以直接转,而二进制转字符串不可以,其中间包含的各种特殊符号,转成字符串时会出现问题,需要将二进制进行base64编码,并且需要在结尾加上#0表示结尾,然后转成字符串.

  5. Sspring bean被初始化加载2次

    Sspring bean被初始化加载2次 spring框架的web项目时,启动的时候发现某个bean被加载了两次,比如使用SchedulingConfigurer或者使用@PostConstruct的 ...

  6. ES6学习笔记(二)-字符串的扩展

    一.字符的 Unicode 表示法 JavaScript 允许采用\uxxxx形式表示一个字符,其中xxxx表示字符的 Unicode 码点. 表示法只限于码点在\u0000~\uFFFF之间的字符, ...

  7. Myeclipse下集成SVN插件

    一.下载SVN插件subclipse   下载地址:http://subclipse.tigris.org/servlets/ProjectDocumentList?folderID=2240   在 ...

  8. 伪元素::before与::after的用法

    ::before与::after两个伪元素其实是CSS3中的内容,然而实际上在CSS2中就已经有了这两者的身影,只不过CSS2中是前面加一个冒号来表示(:before和:after).今天主要讲讲这两 ...

  9. Python爬虫教程-06-爬虫实现百度翻译(requests)

    使用python爬虫实现百度翻译(requests) python爬虫 上一篇介绍了怎么使用浏览器的[开发者工具]获取请求的[地址.状态.参数]以及使用python爬虫实现百度翻译功能[urllib] ...

  10. PHP把下划线分隔命名的字符串与驼峰式命名互转

    最近项目使用symfony框架,这个框架对数据库的操作在这个团队里使用的是ORM进行操作,说实话使用ORM的开发效率和运行效率不一定高多少,到是它的实体命名和现有数据库字段的命名不太一样,ORM实体属 ...