消息队列的基本概念
消息队列提供了一种在两个不相关的进程之间传递数据的简单高效的方法。与有名管道比较起来,消息队列的优点在独立于发送与接收进程,这减少了在打开与关闭有名管道之间同步的困难。
消息队列提供了一种由一个进程向另一个进程发送块数据的方法。另外,每一个数据块被看作有一个类型,而接收进程可以独立接收具有不同类型的数据块。消息队列的好处在于我们几乎可以完全避免同步问题,并且可以通过发送消息屏蔽有名管道的问题。更好的是,我们可以使用某些紧急方式发送消息。坏处在于,与管道类似,在每一个数据块上有一个最大尺寸限制,同时在系统中所有消息队列上的块尺寸上也有一个最大尺寸限制。
Linux的消息队列机制
msgget函数
创建和访问一个消息队列
int msgget(key_t key, int msgflag);
key : 某个消息队列的名字,可通过ftok函数获得,为了确保进程间通信,我们必须保证俩个进程的key值相同。
key_t ftok(const char *pathname, int proj_id);
成功的时候返回一个key值,用于创建消息队列,如果失败,返回-1
msgflag:有两个选项IPC_CREAT和IPC_EXCL,单独使用IPC_CREAT,如果消息队列不存在则创建之,如果存在则打开返回;单独使用IPC_EXCL是没有意义的;两个同时使用,如果消息队列不存在则创建之,如果存在则出错返回。
返回值:成功返回一个非负整数,即消息队列的标识码,失败返回-1
msgctl函数
消息队列的控制函数
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数:
msqid:由msgget函数返回的消息队列标识码
cmd:是将要采取的三个动作。(如下)
三个动作:
- IPC_STAT:该命令用来获取消息队列对应的 msqid_ds 数据结构,并将其保存到 buf 指定的地址空间。
- IPC_SET:该命令用来设置消息队列的属性,要设置的属性存储在buf中。
- IPC_RMID:从内核中删除 msqid 标识的消息队列。
返回值:成功返回0,失败返回-1
msgsnd函数
功能:把一条消息添加到消息队列中
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数:
msgid: 由msgget函数返回的消息队列标识码
msgp: 指针指向准备发送的消息
msgze: msgp指向的消息的长度(不包括消息类型的long int长整型)
msgflg: 默认为0
返回值:成功返回0,失败返回-1
消息结构一方面必须小于系统规定的上限,另一方面必须以一个long int长整型开始,接受者以此来确定消息的类型
struct msgbuf
{
long mtype;
char buff[32];
};
msgrcv函数
从一个消息队列收消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数:与msgsnd相同
返回值:成功返回实际放到接收缓冲区里去的字符个数,失败返回-1。
代码示例
消息队列a.c
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<assert.h>
#include<sys/msg.h>
struct mess //消息结构体
{
long int type;
char buff[32];
};
int main()
{
int msgid=msgget((key_t)1234,IPC_CREAT|0600); //创建消息队列
assert(msgid!=-1);
struct mess dt;
dt.type=1;
strcpy(dt.buff,"ZWL");
msgsnd(msgid,&dt,32,0); //把dt.buff添加到消息队列中去
exit(0);
}
消息队列b.c
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<assert.h>
#include<sys/msg.h>
struct mess
{
long int type;
char buff[32];
};
int main()
{
int msgid=msgget((key_t)1234,IPC_CREAT|0600); //创建消息队列
assert(msgid!=-1);
struct mess dt;
msgrcv(msgid,&dt,32,1,0); //将消息类型位1的消息读取到dt中
printf("read:msg:%s\n",dt.buff);
exit(0);
}
运行如下图所示:
消息队列创建成功后可以通过ipcs -q来查看已经创建的消息队列。