SystemV消息队列
Posted 清水寺扫地僧
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SystemV消息队列相关的知识,希望对你有一定的参考价值。
1. 消息队列概述
- 消息队列提供了一个从一个进程到另外一个进程发送一块数据的方法;
- 每个数据块都被认为是有一个类型,接受者进程接受的数据块可以有不同的类型值;
- 消息队列也有管道一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数也是有上限的(MSGMNB),系统上消息队列的总数也有个上限(MSGMNI),以上限制/上限可以使用如下指令进行查看:
cat /proc/sys/kernel/msg/msgmax (/msgmnb/msgni)
,在内核中实现的数据结构中也有体现,如下; - 内核为每个IPC对象维护一个数据结构:
struct ipc_perm {
key_t __key; /*Key supplied to xxxget(2)*/
uid_t uid; /*Effective UID of owner*/
gid_t gid; /*Effective GID of owner*/
uid_t cuid; /*Effective UID of creator*/
gid_t cgid; /*Effective GID of creator*/
unsigned short mode; /*Permissions*/
unsigned short __seq; /*Sequence number*/
} ;
- 内核当中的消息队列结构:
struct msqid_ds {
struct ipc_perm msg_perm; /* Ownership and permissions */
time_t msg_stime; /* Time of last msgsnd(2) */
time_t msg_rtime; /* Time of last msgrcv(2) */
time_t msg_ctime; /* Time of last change */
unsigned long __msg_cbytes; /* Current number of bytes in queue (nonstandard) */
msgqnum_t msg_qnum; /* Current number of messages in queue */
msglen_t msg_qbytes; /* Maximum number of bytes allowed in queue */
pid_t msg_lspid; /* PID of last msgsnd(2) */
pid_t msg_lrpid; /* PID of last msgrcv(2) */
};
消息队列在内核中的实际形式:
查看消息队列,在shell当中使用ipcs
即可,若是想要删除key值相对应的消息队列,在shell中使用ipcrm -n 数字
即可。
2. 消息队列函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg); //创建或访问一个消息队列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
//控制一个消息队列,如修改一个消息队列控制权限,删除一个消息队列
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); //往消息队列发送消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); //从消息队列读取消息
2.1 msgget 函数
int msgget(key_t key, int msgflg);
- key:某个消息队列的名字;
- msgflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的,详见`man 2 open`;
对于msgflg权限标志,需注意IPC_PRIVATE,IPC_CREAT和IPC_EXCL的用法和作用
- 返回值:成功返回一个非负整数,即该消息队列的标识码;失败返回-1;
msgget函数创建或打开一个IPC对象的逻辑:
2.2 msgctl 函数
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
//控制一个消息队列,如修改一个消息队列控制权限,删除一个消息队列
- msqid:由msgget函数返回的消息队列标识码;
- cmd:是将要采取的动作(有三个值可取)
⑴ IPC_STAT:把msqid_ds结构中的数据设置为消息队列的当前关联值,和*buf参数配合获取msqid消息队列信息;
⑵ IPC_SET:在进程有足够权限的前提下,把消息队列的当前关联值设置为msqid_ds数据结构中给的值;
⑶ IPC_RMID:删除消息队列;
- 返回值:成功返回0, 失败返回 -1;
2.3 msgsnd 函数
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
//把一条消息添加到消息队列中
- msgid:有msgget函数返回的消息队列标识码;
- msgp:是一个指针,指针指向准备发送的消息;
- msgsz:是msgp指向的消息长度,这个长度不含保存消息类型的那个long int长整型;
- msgflg:控制着当前消息队列满或到达上限时将要发生的事;
- 返回值:成功返回0;失败返回-1;
msgflg = IPC_NOWAIT表示队列满不等待,返回EAGAIN错误;
消息结构在两方面受到制约。首先,它必须小于系统规定的上限值;
其次,它必须以一个long int长整数开始,接收者函数将利用这个长整数确定消息类型
消息结构参考形式如下:
struct msgbuf {
long mtype;
char mtext[1];
}
2.4 msgrcv 函数
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
//从消息队列读取消息
- msgid:由msgget函数返回的消息队列标识码;
- msgp:是一个指针,指针指向准备接受的消息;
- msgsz:是msgp指向的消息长度,这个长度不含保存消息类型的那个long int 长整型;
- msgtype:它可以实现接受优先级的简单形式;
msgtype=0返回队列第一条信息;
msgtype>0返回队列第一条类型等于msgtype的消息;
msgtype<0返回队列第一条类型小于等于msgtype绝对值的消息;
- msgflg:控制着队列中没有相应类型的消息可供接受时将要发生的事;
msgflg=IPC_NOWAIT队列没有可读消息不等待,返回ENOMSG错误;
msgflg=MSG_NOERROR消息大小超过msgsz时被截断;
msgtype>0且msgflg=MSC_EXCEPT接收类型不等于msgtype的第一条消息;
- 返回值:成功返回实际放到接收缓冲区里的字符个数,失败返回-1;
以上是关于SystemV消息队列的主要内容,如果未能解决你的问题,请参考以下文章