什么是消息队列

定义:消息队列就是消息的链接表,存放在内核中并且由消息队列表示符标识。

消息是由数据和类型组成的一种内核对对象。是一种临时存储消息的队列,是进程间通信方式的一种,但是和队列不同的是,消息队列并不严格要求遵循先进先出的规则。消息队列的思想和IP数据报的结构思想基本一致,根据数据类型将消息数据分成很多的种类,然后从中检索出进程所需要的数据类型的消息。从而打破了队列先进先出的规则。

消息队列的操作

创建消息队列

#include<sys/msg.h>
int msgget( key_t key, int flag )
函数功能:打开一个现存队列或者创建一个新队列
函数返回值:若成功则返回消息队列的ID,若出错则返回-1

第一个参数的类型是key_t,这是系统基本数据类型。在系统中给出的定义是一个长整形,因此在使用时可以将整形实参传入,也可强转实参传入。

第二个参数的含义是权限。权限都来自与下图。

消息队列中获取数据_消息队列

如果消息队列ID获取成功则可以进行后续三个函数进行操作


消息队列的删除

#include<sys/mgs.h>
int msgctl ( int msgid, int cmd, struct msqid_ds *buf );
函数功能:对当前传入的队列ID进行删除操作。又称(垃圾桶函数)
返回值:成功返回0,若出错返回-1

第一个参数是队列ID

第二个参数是对消息该队列的行为。即传入不同的宏,对消息队列有不同的操作。具体如下:

IPC_STAT      取消次队列的msqid_ds结构,并将此结构保存在buf所指的对象中。(不常用)

IPC_SET        按由buf指向结构中的值,设置与此队列相关结构中的四个字段。(不常用)

IPC_RMID      从系统中删除该消息队列以及仍然在该队列中的所有数据。(注意:此操作会让仍在使用当前队列的进程在下一次试图对此队列进行操作时会返回EIDRM。

此命令只能由两种进程执行。一种是有效用户的ID与创建该队列的用户ID相同,也就是说必须是同一用户创建和删除队列。另一种是超级用户,即root用户)


将数据发送到消息队列

#include<stdio.h>
int msgsnd ( int msgid, const void *ptr, size_t nbytes, int flag );
函数功能:将ptr所指的数据发送到消息队列中
返回值:操作成功返回0,失败返回-1

第一个参数是消息队列的ID

第二个参数是ptr,指向一个长整数,包含正的整型消息类型,其后紧跟着消息数据。数据有无与参数nbytes值有关。

ptr所指向的结构如下:

struct mymesg{
            long mtype;              //消息的类型,为整形值,并不是数据类型
          char mtext[nbytes];        //将进程想要发送的数据存储在mtext数组中。该数组长度为nbytes 
}

第三个参数就是消息数据的长度。如果nbytes是0;则表示无消息数据,如果不为0,表示消息数据的长度。所以,传入消息前必须要定义mymesg,并且初始化。ptr就是指向mymesg结构的指针。接受者根据消息类型以先进先出的次序取得逻辑上的第一个消息。

第四个参数flag指定为IPC_NOWAIT,意为不阻塞。如果函数出错就会立即返回EAGIN,进程不会阻塞运行。如果不指定IPC_NOWAIT,当消息队列满了,再次发送时进程就可能阻塞。阻塞到以下情况:

1、有足够的空间容下新消息,

2、该消息队列被删除了

3、捕捉到信号,采取相应的行动。

从消息队列中获取消息

#include<sys/msg.h>
ssize_t msgrcv( int msgid, void *ptr, size_t nbytes, long type, int flag )
函数功能:进程根据消息类型的值确定一类消息,根据type将获取的消息保存于ptr所指的缓冲区中。
返回值:成功返回消息队列的数据部分的长度,出错返回-1

第一个参数是消息队列的ID

第二个参数是需要传入一个地址,传入的可以是结构体mtest中数组,也可以是基本类型的char数组。

第三个参数是缓冲区的长度

第四个参数是type,通过type的值可以指定我们想要的消息:

        type == 0      返回队列中的第一个消息

        type   >  0     返回队列中的消息类型为type的第一个消息(按照先进先出的规则)

        type   <  0     返回队列中消息类型值小于或者等于type绝对值的消息,如果这种消息有若干个,取类型值最小的消息,而不是遵循先进先出的原则取值。

第五个参数flag,指定值为IPC_NOWAIT,使操作不阻塞。如果没有获取到所指定的类型的消息则函数返回-1,并且将errno设置为ENOMSG。如果没有指定IPC_NOWIT,则进程会阻塞。进程阻塞直到如下情况:

1、有了指定类型的消息

2、从系统中删除了此队列

3、捕捉到一个信号,并且采取相应的行为。