文章目录
一、消息队列的概念
1.定义:
消息队列是消息的链表,存放在内核中并由消息队列标识符表示
。消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法,这个数据块由消息类型和数据等信息组成
。消息队列遵循先进先出的策略,但因为存在消息类型,有优先级,故消息队列类似于一个优先级队列
。
内核为每个消息队列维护了一个数据结构msqid_ds,用于标识消息队列,成员有:
struct msqid_ds{
struct ipc_perm msg_perm; //权限结构体,规定了权限和所有者
time_t msg_stime; //消息队列最后添加消息的时间
time_t msg_rtime; //最后从对队列中获取消息的时间
time_t msg_ctime; //最后一次改变时间
unsigned long _msg_cbytes; //当前输入的字节数
msgqnum_t msg_qnum; //队列中消息的数量
msglen_t msg_qbytes; //队列中允许最大字节数
pid_t msg_lspid; //最后一次添加的消息
pid_t msg_lrpid; //最后一次获取的消息
……
};
通过msg_perm标识一个消息队列,通过msqid_ds表示一个消息队列,根据msg_first,msg_last成员维护一个先进先出的msg链表队列(固定类型),每次发送消息时,将其构造成msg结构对象,即自己定义的消息结构体,里面可以包含消息类型,内容等信息,
并添加到msqid_ds成员维护的链表队列中,如下图所示:
消息队列和管道类似,在消息长度和数目上都有一定的限制,具体的系统限制如下表所示:
导出的:表示这种限制来源于其他限制,如最大消息数是根据最大队列数和队列允许的最大数据量决定的。
可以使用:
cat /proc/sysy/kernel/msgmax 查看具体的数据
2.特点:
- 消息队列可以实现消息的随机读取,消息的类型不固定时,就
不一定以先进先出的次序读取
,可以根据类型的优先级进行读取。 - 消息允许一个或多个进程向它写入或者读取信息。
- 与无名管道,有名管道一样,从消息队列中读出消息,消息队列中对应的数据都会被删除。
- 每个消息队列都有消息队列标识符,在msg_perm中存储,是唯一的标识符。
- 消息队列是消息的链表,存放在内存中,由内核维护,
生命周期随内核
,即只有内核重启或人工删除消息队列时,该消息队列才会被删除,若不人工删除消息队列,消息队列会一直存在于系统中。 - 消息队列可以
双向通信
。 - 克服了管道只能承载无格式字节流的缺点,
不会出现数据粘包的现象,因为消息之间有间隔
。
二、消息队列相关函数
利用消息队列进行进程间铜通讯的方式,我们可以类比为:A需要发送信息给B,但是因为距离原因当面给A,那么就需要A先把信息给XX地址的SS驿站,驿站将其存储,存储箱编号为YYYYY,B要取出这个信息,必须到XX地址的SS驿站取出编号为YYYYY的箱子,打开才可以获取。
在消息队列中,键(key)值相当于XX地址,消息队列标识符相当于SS驿站,消息类型相当于YYYYY编号的箱子。
同一个键(key)值可以保证是同一个消息队列,同一个消息队列标识符才能保证不同进程可以相互通信,同一个消息类型才能保证某个进程取出的是对方的信息。
1.键值
System V提供的进程间通信机制需要一个key值,通过key值就可以在系统内获得一个唯一的消息队列标识符, key值可以是人为指定的数字,强转为key_t类型即可,也可以通过ftok 函数获得。
- 人为指定
(key_t)1234;//1234就为key值,在创建获取消息队列函数的第一个参数可以这样写
- 通过函数获得key值
# include<sys/types.h>
# include<sys/ipc.h>
key_t ftok(const char* pathname,int proj_id);
成功返回key值,