介绍
消息队列是一种以链表式结构组织的数据,存放在内核中,是三个IPC对象类型中最具数据操作性的数据传送方式,可以根据数据类型来检索消息。
ipcs -q查看
ipcrm -q [msqid] 删除
消息队列创建/打开
int msgget(key_t key, int msgflg);
第一个参数key:给这个消息队列分配的密钥,同创建共享内存一样,系统返回对应共享内存的标识符,失败返回-1
第二个参数msgflg:IPC_CREAT如果不存在就创建,IPC_EXCL如果已经存在则返回失败,位或权限位:可以设置消息队列的访问权限
每创建一个消息队列,就会在用户空间组织这样的一个数据结构,用来设置或返回消息队列的信息。
struct msqid_ds {
struct ipc_perm msg_perm;
struct msg *msg_first; // 消息队列第一个节点
struct msg *msg_last; // 消息队列最后一个节点
unsigned short msg_cbytes; // 当前队列字节数据
unsigned short msg_qnum; // 队列中的消息数
unsigned short msg_qbytes; // 队列中最大字节数
...
// 时间属性
// 最近接收和发送消息的进程pid
};
其中ipc_perm结构体中组织了消息队列的key,创建/所有者ID和组ID,对象访问权限,消息队列中的消息数目。
当创建一个新的消息队列时,ipc_perm结构体中,创建/所有者ID被设置为当前用户ID,创建/所有者组ID被设置为当前用户组ID,其中对象访问权限被设置为msgflg,msg_ctime被设置为当前时间;msg_qbytes被设置为系统限制值MSGMNB。
添加消息到消息队列中
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
msgid:msgget函数返回的消息队列标识符
msgp:指向准备发送的消息,是一个用户自定义的结构体
msgsz:消息⻓度,不含消息类型,最大长度MSGMAX
msgflg:IPC_NOWAIT队列满非阻塞,返回EAGAIN错误,0阻塞
msgp的格式:
struct msgstru {
long mtype;/*必须大于0*/
char mtext[用户指定的大小]
}
将数据添加到队列尾,并且更新msg_last
从消息队列中接收消息
ssize_t msgrcv(int msqid,void *msgp,size_t msgsz,long msgtyp,int msgflg);
msgid:msgget函数返回的消息队列标识符
msgp:指针指向准备接收的消息
msgsz:是msgp指向的消息⻓度,不含消息类型
msgtype:它可以实现接收优先级的简单形式
若=0 - 读取消息队列中最早的消息,以先进先出的方式读取消息。
若> 0 - 读取消息队列类型为msgtyp最早的消息。
若< 0 - 读取消息队列中,消息类型小于或等于msgtyp绝对值的消息中最小消息类型的最早消息。
msgflg:IPC_NOWAIT设置非阻塞
成功返回实际放到msgp⾥去的字符个数,失败返回-1
控制消息队列
int msgctl(int msqid,int cmd,struct msqid_ds* buf);
msgid:msgget函数返回的消息队列标识符
通常cmd为IPC_RMID,buf为空,和共享内存相似
从内核看本质
内核维护着一个消息队列的全局数据结构ipc_ids,其中有一个指针指向一个数组。每当创建一个IPC对象内核就会创建一个ipc_perm,并且将它的地址放到结构体ipc_id中,这个数组就是这个结构体ipc_id组成的数组,数组最大的个数就是MSGMNI,所以说消息队列随内核持续,直到内核重新自举或者显示删除该对象为止。类似还有信号量、共享内存。