1.什么是消息队列
- 消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法
- 每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值
- 消息队列也有管道一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI)
cat /proc/sys/kernel/msgmax
cat /proc/sys/kernel/msgmnb
cat /proc/sys/kernel/msgmni
2.IPC对象数据结构
内核为每个IPC对象维护一个数据结构
struct ipc_perm{
key_t __key; //关键字 Key supplied to xxxget(2)
uid_t uid;
gid_t gid;
uid_t cuid;
gid_t cgid;
unsigned short mode; // 访问权限
unsigned short __seq; //队列号
}
3.消息队列数据结构
struct msgid_ds{
struct ipc_perm msg_perm; // IPC结构
time_t msg_stime; // time of last msgsnd
time_t msgrtiem; //time of last msgrcv
time_t msg_ctime; //time of last change
unsigned long __msg_cbytes; //current number of bytes in queue
msgqnum_t msg_qnum; //current numbers of messages in queue
msglen_t msg_qbytes; //maximum number of bytes allowed in queue
pid_t msg_lspid; //pid of last msgsnd
pid_t msg_lrpid; //pid of last msgrcv
}
4.消息队列函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
4.1 msgget函数
- 功能,用来创建和访问一个消息队列
- 原型
int msgget(key_t key, int msgflg);
//key:某个消息队列的名字
//msgflg:由九个权限表示构成,它们的用法和创建文件时使用的mode模式标志是一样的
int msgid;
msgid = msgget(1234, 0666 | IPC_CREAT | IPC_EXCL);
msgid = msgget(IPC_PRIVATE, 0666 | IPC_CREAT | IPC_EXCL);//总是能创建一个新的消息队列
msgid = msgget(IPC_PRIVATE, 0666); //作用类似上面
- 返回值:成功返回一个非负整数,即该消息队列的标识码,失败返回-1
ipcs,查看消息队列
ipcrm -q xxx(msgid),删除某个消息队列
ipcrm -Q xxx(key),删除某个消息队列
4.2 msgctl函数
- 功能,消息队列的控制函数
- 原型
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
//msqid:由msgget函数返回的消息队列标识码
//cmd:将要采取的动作,有三个可取值,如下三个IPC_
//IPC_STAT:把msqid_ds结构中的数据设置为消息队列的当前关联值
int msgid = msgget(1234, 0);//打开一个已创建的消息队列
struct msqid_ds buf;
msgctl(msgid, IPC_STAT, &buf);//获取该消息队列的消息,保存在buf中
printf("mode=%o\n", buf.msg_perm.mode);
//IPC_SET:在进程有足够权限的前提下,把消息队列的当前关联值设置为msqid_ds数据结构中给出的值
int msgid = msgget(1234, 0);//打开一个已创建的消息队列
struct msqid_ds buf;
msgctl(msgid, IPC_STAT, &buf);//获取该消息队列的消息,保存在buf中
printf("mode=%o\n", buf.msg_perm.mode);
sscanf("600", "%o", (unsigned int*)&buf.msg_perm.mode);
msgctl(msgid, IPC_SET, &buf);
printf("mode=%o\n", buf.msg_perm.mode);
//IPC_RMID:删除消息队列
int msgid = msgget(1234, 0);//打开一个已创建的消息队列
msgctl(msgid, IPC_RMID, NULL);//删除msgid消息队列
- 返回值,成功返回0,失败返回-1
4.3 msgsnd函数
- 功能,把一条消息添加到消息队列中
- 原型
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
//msgid:由msgget函数返回的消息队列标识码
//msgp:是一个指针,指针指向准备发送的消息
//msgsz:是msgp指向的消息长度,这个长度不含保存消息类型的那个long int长整型
//msgflg:控制着当前消息队列满或到达系统上限时将要发送的事情
msgflg=IPC_NOWAIT表示队列满不等待,返回EAGAIN错误,=0表示满了继续等待。
消息结构在两方面受到制约(MSGMAX)。首先,它必须小于系统规定的上限值;其次,它必须以一个long int长整数开始,接收者函数将利用这个长整数确定消息类型。
消息结构参考形势如下:
struct msgbuf{
long mtype;
char mtext[1];
}
- 返回值,成功返回0,失败返回-1
4.4 msgrcv函数
- 功能,是从一个消息队列接收消息
- 原型
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
//msgid:由msgget函数返回的消息队列标识码
//msgp:是一个指针,指针指向准备接收的消息
//msgsz:是msgp指向的消息长度,这个长度不含保存消息类型的那个long int长整型
//msgtype:它可以实现接收优先级的简单形式
//msgflg:控制着当前消息队列没有相应类型的消息可供接收时将要发送的事情
msgtype=0,返回队列第一条消息;
msgtype>0,返回队列第一条类型等于msgtype的消息;
msgtype<0,返回队列第一条类型小于等于msgtype绝对值的消息,先接收最小的;
msgflg=IPC_NOWAIT表示队列没有可读消息不等待,返回ENOMSG错误;
msgflg=MSG_NOERROR,消息大小超过msgsz时被截断;
msgtype>0且msgflg=MSG_EXCEPT,接收类型不等于msgtype的第一条消息。
- 返回值,成功返回实际放到接收缓冲区里的字符个数,失败返回-1