1. 概念

消息队列就是一个消息的链表。可以把消息看作是一个记录,具有特定的格式。进程可以向中按照一定的规则添加新消息;另一些进程则可以从消息队列中读取消息。

2. 分类

  • POSIX消息队列
  • 系统V消息队列

3. 特性

系统V消息队列是随内核持续的,只有在内核重起或者人工删除时,该消息队列才会被删除。

4. 创建键值

消息队列的内核持续性要求每个消息队列都在系统范围内对应唯一的键值,所以,要获得一个消息队列的描述字,必须提供该消息队列的键值。

4.1 函数定义

#include <sys/types.h>
#include <sys/ipc.h>

key_t ftok(char* pathname, char proj);

4.2 功能

返回文件名对应的键值。

4.3 参数

pathname: 文件名

proj: 项目名(不为0即可)

5. 创建消息队列

5.1 函数类型

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);

5.2 返回值

与键值key相对应的消息队列的描述字。

5.3 参数

key: 键值,由ftok获得

msgflg: 标志位

IPC_CREAT:创建新的消息队列
IPC_EXCL:与IPC_CREAT一同使用,表示如果要创建的消息队列已经存在,则返回错误
IPC_NOWAIT:读写消息队列要求无法得到满足时,不阻塞

在以下两种情况下,将创建一个新的消息队列:

  • 如果没有与键值key相对应的消息队列,并且msgflg中包含了IPC_CREAT标志位;
  • key的参数为IPC_PROVATE;

一个实例:

int open_queue(key_t keyval)
{
    int qid = msgget(keyval, IPC_CREAT);
    if(-1 == qid)
    {
        return -1;
    }

    return qid;
}

6. 发送消息

向消息队列发送一条消息。

6.1 函数类型

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgsnd(int msgid, struct msgbuf* msgp, int msgsz, int msgflg);

6.2 返回值

成功返回0,失败返回-1

6.3 参数

  • msgid: 已打开消息队列的id
  • msgp: 存放消息的结构
struct msgbuf
{
    long mtype;    //消息类型 > 0
    char mtext[1]; //消息数据的首地址
}
  • msgsz: 发送消息的长度
  • msgflg: 发送标志,有意义的msgflg标志为IPC_NOWAIT,指明在消息队列没有足够空间容纳要发送的消息时,msgsnd是否等待

7. 接收消息

7.1 函数定义

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgrcv(int msqid, struct msgbuf* msgp, int msgsz, long msgtyp, int msgflg);

从msqid代表的消息队列中读取一个msgtyp类型的消息,并把消息存储在msgp指向的msgbuf结构中。在成功的读取了一条消息以后,队列中的这条消息将被删除。

7.2 返回值

成功返回消息数据部分的长度(注意减去数据类型),失败返回-1

7.3 参数

  • msgid: 消息队列的id
  • msgp: 存放消息的结构
  • msgtyp: 消息类型
  • msgsz: 接收消息的长度
  • msgflg: 接收标志

一个实例:

int read_message(int qid, long type, struct mymsgbuf* qbuf)
{
    int length = sizeof(struct mymsgbuf) - sizeof(long);
    int result = msgrcv(qid, qbuf, length, type, 0);
    if(-1 == result)
        return -1;

    return result;
}

8. 实例

#include <sys/types.h>
#include <sys/msg.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

struct msg_buf
{
    int mtype;
    char data[255];
};

int main()
{
    key_t key;
    int msgid;
    int ret;
    struct msg_buf msgbuf;

    key = ftok("./test", 'a');
    printf("key = [%x]\n", key);
    
    msgid = msgget(key, IPC_CREAT|0666);
    if(-1 == msgid)
    {
        printf("create error!\n");
        return -1;
    }

    msgbuf.mtype = getpid();    
    strcpy(msgbuf.data, "test queue!");
    
    ret = msgsnd(msgid, &msgbuf, sizeof(msgbuf.data), IPC_NOWAIT);
    if(-1 == ret)
    {
        printf("msgsnd error!, ret = %d\n", ret);
        return -1;
    }

    memset(&msgbuf, 0, sizeof(msgbuf));
    ret = msgrcv(msgid, &msgbuf, sizeof(msgbuf.data), getpid(), IPC_NOWAIT);
    if(-1 == ret)
    {
        printf("msgrcv error! ret = %d\n", ret);
        return -1;
    }
    printf("recv msg = [%s]\n", msgbuf.data);

    return 0;
}