消息队列以链表的方式将消息存储于内核中,调用msgsnd,msgrcv函数往消息队列里面投送,取出指定的消息。
生成一个消息队列或者获取已有消息队列id
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgget(key_t key, int msgflg);
msgget函数返回key值对应的消息队列id。
1. key是一个用来与一个ipc对象进行对应的东西,起到在内核中标识的作用。
2.返回的id起到的是外部也就是我们应用层的标识作用,例如所有操作消息队列的函数,都是用msgid来唯一确定一个消息队列。
3.msgflg用来指定消息队列的权限,操作属性,高位为操作属性,地位为操作权限,比如msgflg通常使用的高位值:
IPC_CREAT:用来创建一个消息队列
IPC_EXCL:查询由key指定的消息队列释放存在
IPC_NOWAIT:之后的消息队列操作都为非阻塞
一个例子 msgget(key, IPC_CREAT|0666); 创建由key指定的消息队列,操作权限为0666。
id = msgget(key, 0666) 得到key值对应的消息队列的id。
当key值为 IPC_PRIVATE 时,或者key值不为它但是msgflg指定了 IPC_CREAT ,则创建一个新的消息队列,如果这个消息队列不存在时。指定 IPC_PRIVATE 为key值时,总是创建一个新的消息队列,生成的消息队列key值为0。
由此可见获得消息队列操作 ID是很关键的,一般有3种方法获得id:
1.指定key值为 IPC_PRIVATE ,创建一个新的消息队列,让后将id值写入一个文件,另一个进程读取该文件,获得id值,这样2个进程就可以通过这个消息队列通信了。
2.手动指定key值为某个值,多个进程都看看得到这个key,这样做的问题就是可能有一个key值和指定key值一样的消息队列存在了,需要处理这样的错误,换一个key值。
3.使用ftok函数生成一个key,同一个key调用msgget得到的id肯定是相同的。
#include <sys/types.h> #include <sys/ipc.h> key_t ftok(const char *pathname, int proj_id); (proj_id is 1-255)
ftok函数的实现是通过stat函数获取pathname的st_dev,st_ino成员(部分位)和proj_id(只用低8位)进行组合生成一个key值,这样做的话,只要pathname和proj_id确定,那么key值基本就确定。
1.但是这个函数依然存在一种可能就是pathname不一样,proj_id一样,仍然得到一个一样的key,这是因为st_dev,st_ino成员数据被截断了,可能刚好保留的数据是相同的。
2.还有一点就是必须确保pathname这个文件全程都不会被改动,否则A进程获得key之后,在B进程获取key之前,修改pathname这个文件,从而影响st_dev,st_ino,导致B得到的key和A不一样,虽然pathname,proj_id并没有变。
通过 msgctl可以获得,设置,删除消息队列
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgctl(int msqid, int cmd, struct msqid_ds *buf);
它的使用类似io操作中的ioctl。cmd有如下值:
IPC_STAT:获取由msgid指定的消息队列的描述结构体,存放于buf中。
IPC_SET:设置消息队列的描述结构体
IPC_RMID:立刻删除指定key值的消息队列,key值存放于buf结构体中。如果删除后仍有进程读写这个消息队列,则返回EIDRM错误。
一般,如果消息队列出错了,使用IPC_RMID删除消息队列,释放它在内核中占有的资源。
原文:http://www.cnblogs.com/thammer/p/5106560.html