IPC通信:Posix消息队列

 消息队列可以认为是一个链表。进程(线程)可以往里写消息,也可以从里面取出消息。一个进程可以往某个消息队列里写消息,然后终止,另一个进程随时可以从消息队列里取走这些消息。这里也说明了,消息队列具有随内核的持续性,也就是系统不重启,消息队列永久存在。

创建(并打开)、关闭、删除一个消息队列

  #include <stdio.h>
#include <stdlib.h>
#include <mqueue.h> //头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h> #define MQ_NAME ("/tmp")
#define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限 int main() {
mqd_t posixmq;
int rc = ; /*
21 函数说明:函数创建或打开一个消息队列
22 返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中
23 */
posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL); if(- == posixmq)
{
perror("创建MQ失败");
exit();
} /*
33 函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写
34 返回值:成功返回0,失败返回-1,错误原因存于errno中
35 */
rc = mq_close(posixmq);
if( != rc)
{
perror("关闭失败");
exit();
} /*
44 函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问
45 返回值:成功返回0,失败返回-1,错误原因存于errno中
46 */
rc = mq_unlink(MQ_NAME);
if( != rc)
{
perror("删除失败");
exit();
} return ;
} 编译并执行: root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c
/tmp/ccZ9cTxo.o: In function `main':
crtmq.c:(.text+0x31): undefined reference to `mq_open'
crtmq.c:(.text+0x60): undefined reference to `mq_close'
crtmq.c:(.text+0x8f): undefined reference to `mq_unlink'
collect2: ld returned exit status
因为mq_XXX()函数不是标准库函数,链接时需要指定;库-lrt;
root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt root@linux:/mnt/hgfs/C_libary# ./crtmq
最后程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息:
root@linux:/mnt/hgfs/C_libary# ./crtmq
创建MQ失败: File exit() 编译这个程序需要注意几点: 、消息队列的名字最好使用“/”打头,并且只有一个“/”的名字。否则可能出现移植性问题;(还需保证在根目录有写权限,为了方便我在root权限下测试)
、创建成功的消息队列不一定能看到,使用一些方法也可以看到,本文不做介绍;   消息队列的名字有如此规定,引用《UNIX网络编程 卷2》的相关描述: mq_open,sem_open,shm_open这三个函数的第一个参数是
一个IPC名字,它可能是某个文件系统中的一个真正存在的路径名,也可能不是。Posix.1是这样描述Posix IPC名字的。
)它必须符合已有的路径名规则(最多由PATH_MAX个字节构成,包括结尾的空字节)
)如果它以斜杠开头,那么对这些函数的不同调用将访问同一个队列,否则效果取决于实现(也就是效果没有标准化)
)名字中的额外的斜杠符的解释由实现定义(同样是没有标准化) 因此,为便于移植起见,Posix IPC名字必须以一个斜杠打头,并且不能再包含任何其他斜杠符。 IPC通信:Posix消息队列读,写 创建消息队列的程序: #include <stdio.h>
#include <stdlib.h>
#include <mqueue.h> //头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h> #define MQ_NAME ("/tmp")
#define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限 int main() {
mqd_t posixmq;
int rc = ; /*
21 函数说明:函数创建或打开一个消息队列
22 返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中
23 */
posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL); if(- == posixmq)
{
perror("创建MQ失败");
exit();
} /*
33 函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写
34 返回值:成功返回0,失败返回-1,错误原因存于errno中
35 */
rc = mq_close(posixmq);
if( != rc)
{
perror("关闭失败");
exit();
} #if 0
/*
45 函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问
46 返回值:成功返回0,失败返回-1,错误原因存于errno中
47 */
rc = mq_unlink(MQ_NAME);
if( != rc)
{
perror("删除失败");
exit();
} return ;
#endif
} 编译并执行: root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt
root@linux:/mnt/hgfs/C_libary# ./crtmq
程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息:
root@linux:/mnt/hgfs/C_libary# ./crtmq
创建MQ失败: File exit()
向消息队列写消息的程序: 消息队列的读写主要使用下面两个函数:
/*头文件*/
#include <mqueue.h> /*返回:若成功则为消息中字节数,若出错则为-1 */
int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio); /*返回:若成功则为0, 若出错则为-1*/
ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio); /*消息队列属性结构体*/
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 */
}; #include <stdio.h>
#include <stdlib.h>
#include <mqueue.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h> /*向消息队列发送消息,消息队列名及发送的信息通过参数传递*/
int main(int argc, char *argv[])
{
mqd_t mqd;
char *ptr;
size_t len;
unsigned int prio;
int rc; if(argc != )
{
printf("Usage: sendmq <name> <bytes> <priority>\n");
exit();
} len = atoi(argv[]);
prio = atoi(argv[]); //只写模式找开消息队列
mqd = mq_open(argv[], O_WRONLY);
if(- == mqd)
{
perror("打开消息队列失败");
exit();
} // 动态申请一块内存
ptr = (char *) calloc(len, sizeof(char));
if(NULL == ptr)
{
perror("申请内存失败");
mq_close(mqd);
exit();
} /*向消息队列写入消息,如消息队列满则阻塞,直到消息队列有空闲时再写入*/
rc = mq_send(mqd, ptr, len, prio);
if(rc < )
{
perror("写入消息队列失败");
mq_close(mqd);
exit();
} // 释放内存
free(ptr);
return ;
} 编译并执行: root@linux:/mnt/hgfs/C_libary# gcc -o sendmq sendmq.c -lrt
root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp
root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp
root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp
root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp
  上面先后向消息队列“/tmp”写入了四条消息,因为先前创建的消息队列只允许存放3条消息,本次第四次写入时程序会阻塞。直到有另外进程从消息队列取走消息后本次写入才成功返回。 读消息队列: #include <stdio.h>
#include <stdlib.h>
#include <mqueue.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h> /*读取某消息队列,消息队列名通过参数传递*/
int main(int argc, char *argv[])
{
mqd_t mqd;
struct mq_attr attr;
char *ptr;
unsigned int prio;
size_t n;
int rc; if(argc != )
{
printf("Usage: readmq <name>\n");
exit();
} /*只读模式打开消息队列*/
mqd = mq_open(argv[], O_RDONLY);
if(mqd < )
{
perror("打开消息队列失败");
exit();
} // 取得消息队列属性,根据mq_msgsize动态申请内存
rc = mq_getattr(mqd, &attr);
if(rc < )
{
perror("取得消息队列属性失败");
exit();
} /*动态申请保证能存放单条消息的内存*/
ptr = calloc(attr.mq_msgsize, sizeof(char));
if(NULL == ptr)
{
printf("动态申请内存失败\n");
mq_close(mqd);
exit();
} /*接收一条消息*/
n = mq_receive(mqd, ptr, attr.mq_msgsize, &prio);
if(n < )
{
perror("读取失败");
mq_close(mqd);
free(ptr);
exit();
} printf("读取 %ld 字节\n 优先级为 %u\n", (long)n, prio);
return ;
} 编译并执行: root@linux:/mnt/hgfs/C_libary# vi readmq.c
root@linux:/mnt/hgfs/C_libary# vi readmq.c
root@linux:/mnt/hgfs/C_libary# gcc -o readmq readmq.c -lrt
root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
读取 字节
优先级为
root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
读取 字节
优先级为
root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
读取 字节
优先级为
root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
读取 字节
优先级为
root@linux:/mnt/hgfs/C_libary# ./readmq /tmp   程序执行五次,第一次执行完,先前阻塞在写处的程序成功返回。第五次执行,因为消息队列已经为空,程序阻塞。直到另外的进程向消息队列写入一条消息。另外,还可以看出Posix消息队列每次读出的都是消息队列中优先级最高的消息。 IPC通信:Posix消息队列的属性设置 Posix消息队列的属性使用如下结构存放:
struct mq_attr
{
long mq_flags; /*阻塞标志位,0为非阻塞(O_NONBLOCK)*/
long mq_maxmsg; /*队列所允许的最大消息条数*/
long mq_msgsize; /*每条消息的最大字节数*/
long mq_curmsgs; /*队列当前的消息条数*/
};
队列可以在创建时由mq_open()函数的第四个参数指定mq_maxmsg,mq_msgsize。 如创建时没有指定则使用默认值,一旦创建,则不可再改变。
队列可以在创建后由mq_setattr()函数设置mq_flags #include <mqueue.h> /*取得消息队列属性,放到mqstat地fh*/
int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat); /*设置消息队列属性,设置值由mqstat提供,原先值写入omqstat*/
int mq_setattr(mqd_t mqdes, const struct mq_attr *mqstat, struct mq_attr *omqstat); 均返回:若成功则为0,若出错为- 程序获取和设置消息队列的默认属性:
#include <stdio.h>
#include <stdlib.h>
#include <mqueue.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h> #define MQ_NAME ("/tmp")
#define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限 int main()
{
mqd_t posixmq;
int rc = ; struct mq_attr mqattr; // 创建默认属性的消息队列
posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);
if(- == posixmq)
{
perror("创建MQ失败");
exit();
} // 获取消息队列的默认属性
rc = mq_getattr(posixmq, &mqattr);
if(- == rc)
{
perror("获取消息队列属性失败");
exit();
} printf("队列阻塞标志位:%ld\n", mqattr.mq_flags);
printf("队列允许最大消息数:%ld\n", mqattr.mq_maxmsg);
printf("队列消息最大字节数:%ld\n", mqattr.mq_msgsize);
printf("队列当前消息条数:%ld\n", mqattr.mq_curmsgs); rc = mq_close(posixmq);
if( != rc)
{
perror("关闭失败");
exit();
} rc = mq_unlink(MQ_NAME);
if( != rc)
{
perror("删除失败");
exit();
}
return ;
} 编译并执行:
root@linux:/mnt/hgfs/C_libary# gcc -o attrmq attrmq.c -lrt
root@linux:/mnt/hgfs/C_libary# ./attrmq
队列阻塞标志位:
队列允许最大消息数:
队列消息最大字节数:
队列当前消息条数:
root@linux:/mnt/hgfs/C_libary# 设置消息队列的属性: #include <stdio.h>
#include <stdlib.h>
#include <mqueue.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h> #define MQ_NAME ("/tmp")
#define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限 int main()
{
mqd_t posixmq;
int rc = ; struct mq_attr mqattr; // 创建默认属性的消息队列
mqattr.mq_maxmsg = ; // 注意不能超过系统最大限制
mqattr.mq_msgsize = ;
//posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL);
posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, &mqattr); if(- == posixmq)
{
perror("创建MQ失败");
exit();
} mqattr.mq_flags = ;
mq_setattr(posixmq, &mqattr, NULL);// mq_setattr()只关注mq_flags,adw // 获取消息队列的属性
rc = mq_getattr(posixmq, &mqattr);
if(- == rc)
{
perror("获取消息队列属性失败");
exit();
} printf("队列阻塞标志位:%ld\n", mqattr.mq_flags);
printf("队列允许最大消息数:%ld\n", mqattr.mq_maxmsg);
printf("队列消息最大字节数:%ld\n", mqattr.mq_msgsize);
printf("队列当前消息条数:%ld\n", mqattr.mq_curmsgs); rc = mq_close(posixmq);
if( != rc)
{
perror("关闭失败");
exit();
} rc = mq_unlink(MQ_NAME);
if( != rc)
{
perror("删除失败");
exit();
} return ;
}
复制代码
编译运行: 复制代码
root@linux:/mnt/hgfs/C_libary# gcc -o setattrmq setattrmq.c -lrt
root@linux:/mnt/hgfs/C_libary# ./setattrmq
队列阻塞标志位:
队列允许最大消息数:
队列消息最大字节数:
队列当前消息条数:
本文转自:http://blog.csdn.net/liuhongxiangm/article/details/8716232

IPC通信:Posix消息队列的更多相关文章

  1. Unix IPC之Posix消息队列(1)

    部分参考:http://www.cnblogs.com/Anker/archive/2013/01/04/2843832.html IPC对象的持续性:http://book.51cto.com/ar ...

  2. Unix IPC之Posix消息队列(3)

    struct mq_attr { long mq_flags; /* message queue flag : 0, O_NONBLOCK */ long mq_maxmsg; /* max numb ...

  3. Unix IPC之Posix消息队列(2)

    /* Query status and attributes of message queue MQDES. */ extern int mq_getattr (mqd_t __mqdes, stru ...

  4. Linux IPC POSIX 消息队列

    模型: #include<mqueue.h> #include <sys/stat.h> #include <fcntl.h> mq_open() //创建/获取消 ...

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

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

  6. UNIX IPC: POSIX 消息队列 与 信号

    POSIX消息队列可以注册空队列有消息到达时所触发的信号,而信号触发对应的信号处理函数. 下面是一份基本的消息队列和信号处理结合的代码(修改自UNIX网络编程:进程间通信) #include < ...

  7. UNIX IPC: POSIX 消息队列

    首先在我的MAC OSX上试了一下虽然有_POSIX_MESSAGE_PASSING的宏定义,但是用gcc编译会提示没有mqueue.h头文件,先放一边.在Ubuntu上使用正常,不过POSIX消息队 ...

  8. [转]Linux进程通信之POSIX消息队列

    进程间的消息队列可以用这个实现,学习了下. http://blog.csdn.net/anonymalias/article/details/9799645?utm_source=tuicool&am ...

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

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

随机推荐

  1. 关于iOS 类扩展Extension的进一步理解

    很多人可能会问  iOS的分类和扩展的区别,网上很多的讲解,但是一般都是分类讲的多,而这也是我们平常比较常用的知识:但是,对于扩展,总觉得理解的朦朦胧胧,不够透彻. 这里就讲一下我自己的理解,但是这个 ...

  2. 【LeetCode】39. Combination Sum (2 solutions)

    Combination Sum Given a set of candidate numbers (C) and a target number (T), find all unique combin ...

  3. 避免全表扫描的sql优化

    对查询进行优化,应尽量避免全表扫描,首先应考虑在where 及order by 涉及的列上建立索引:  .尝试下面的技巧以避免优化器错选了表扫描: ·   使用ANALYZE TABLE tbl_na ...

  4. Linux内核(16) - 高效学习Linux内核

    世界悲结束了,章鱼哥也退役了,连非诚勿扰中的拜金女也突然的少了很多.这本<Linux内核修炼之道>在卓越.当当.china-pub上也已经开卖了,虽然是严肃文学,但为了保证流畅性,大部分文 ...

  5. Linux内核“问题门” - 学习问题、经验集锦

    陈宪章说:“学贵有疑,小疑则小进,大疑则大进.疑者,觉悟之机也,一番觉悟一番长进.” 培根说:“多问的人将多得.” 还在学校的时候导师在激情讲演之后对着会议室里形态各异但均静默不语的我们痛心疾首的说: ...

  6. Java调用Linux命令(cd的处理)

    一.Java调用Linux系统的命令非常简单 这是一个非常常用的调用方法示例: public String executeLinuxCmd(String cmd) { System.out.print ...

  7. MySQL日期与时间戳互转函数

    -- 时间戳转日期 ); #日期转时间戳 Select UNIX_TIMESTAMP('2018-07-16 12:23:00');

  8. sureface 屏幕残影问题官方解决方案 - 卸载显卡驱动

    您进入桌面,左下角微软图标(单击右键),选择设备管理器,点开“显示适配器”前面的小三角,找到“Intel(r) hd gRAPHICS 520”, 单击右键卸载,卸载的时候不要勾选“删除此设备的驱动软 ...

  9. Android开发13——内容提供者ContentProvider的基本使用

    一.ContentProvider简介 当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据.ContentProvider为存储和获取数据提 ...

  10. 使用xtrabackup(innobackupex)实现MySQL的热备

    mysql 的热备http://www.178linux.com/10139http://www.linuxidc.com/Linux/2014-04/99671.htmhttp://634871.b ...