Syetem V消息队列
System V消息队列的一些基本特征
- 通过消息队列进行的通信是面向消息的,即读者接收到有写者写入的整条消息,读取消息的一部分或者一次读取多条消息的操作都是做不到的
- 每条消息包含有一个用整数表示的类型,可以根据顺序读取消息,也可以根据消息的类型读取消息
1.创建/打开一个消息队列
msgget()用于创建一个新消息队列或者用于获取一个已有的消息队列
#include<sys/types.h>
#include<sys/msg.h>
int msgget(key_t key, int msgflg);
//成功:返回0 失败:返回 -1
参数解释:
-
key
用于生成/获取消息队列的键,可由IPC_PRIVATE或者ftok()产生
-
msgflg
用于指定新生成的消息队列的权限,或者检查一个已有的消息队列的权限
有以下取值
值 描述 IPC_CREAT 如果没有指定的key对应的消息队列,那么就创建一个新队列 IPC_EXCL 与IPC_CREAT搭配使用,用于创建新队列
2.发送消息
msgsnd()用于向消息队列发送消息
#include <sys/types.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgz, int msgflg);
//成功:返回 0 失败:返回-1
参数解释:
-
msqid
消息队列标识符
-
msgp
msgp是一个指向自定义结构体的指针,该结构体通常被定义成如下形式
struct mymsg{ long mtype; //消息类型 char mtext[]; //消息文本 }
- 当使用msgsnd()发送消息时,mtype字段必须大于0
-
msgz
指定了msgp所指结构体的mtext[]字段大小
-
msgflg
有如下取值
-
IPC_NOWAIT
执行一个非阻塞的发送操作,通常情况下,当消息队列已满时,发送操作会陷入阻塞,如果指定IPC_NOWAIT标志后,则会在队列满并且发送消息时立即返回EAGAIN错误
-
3.接受消息
msgrcv()系统调用从消息队列中读取(并且删除)一条消息并且复制到msgp所指向的缓冲区
#include <sys/types.h>
#include <sys/msg.h>
ssize_t msgrcv(int msgid, void*msgp, size_t maxmsgz, long msgtyp, int msgflg);
//成功:返回读取到mtext的字节数 失败:返回-1
参数解释
-
msgid
消息队列标识符
-
msgp
指向消息队列缓冲区
-
maxmsgz
表明msgp缓冲区中mtext字段的最大可用空间,如果消息队列中待删除的消息体的大小超过了maxmsgsz字节,那么就不会从消息队列中删除消息(除非指定了MSG_NOERROR)标志
-
msgtyp
根据该参数指定如果读取消息队列中的消息
-
msgtyp 等于0
删除队列中的第一条消息并将其返回给调用进程
-
msgtyp大于0
将队列中第一条mtype等于msgtyp的消息删除并将其返回给调用进程,通常将msgtyp指定为进程pid
-
msgtyp小于0
将队列中mtype最小并且其值小于或等于msgtyp的绝对值的第一条消息删除并返回给调用进程
-
-
msgflg
有以下取值
-
IPC_NOWAIT
非阻塞,当队列中没有匹配msgtyp的消息时不阻塞而是立即返回ENOMSG
-
MSG_EXCEPT
只有当msgtyp大于0时这个标记才会有作用,将消息队列中第一条mtype不等于msgtyp的消息删除并返回给调用者
该标记为Linux特有,并且需要指定_GNU_SOUORCE
-
MSG_NOERROR
如果消息的mtext字段大小超过了可用空间,那么指定该字段后,将会从队列中删除消息并且将mtext字段的大小截断
为maxmsgsz字节
-
msgsnd(),msgrcv()与信号
当msgsnd()/msgrcv()发生阻塞时,它们有可能被信号处理器中断,当发生这种情况时,msgsnd()/msgrcv()总是会返回EINTR错误,
即使信号处理器设置了SA_RESTART标志,调用也不会重启
4.消息队列控制
msgctl()系统调用在标识符为msqid的消息队列上执行控制操作
#include <sys/types.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
//成功:返回0 失败:返回-1
cmd参数可以取如下值
5.消息队列关联数据结构
每个消息队列都有一个与之相关的数据结构
struct msqid_ds {
struct ipc_perm msg_perm; //所有权以及权限
time_t msg_stime; //上一次msgsnd()的时间
time_t msg_rtime; //上一次msgrcv()的时间
time_t msg_ctime; //上一次状态改变的时间
unsigned long __msg_cbytes; //队列中的字节总数
msgqnum_t msg_qnum; //队列中的消息总数
msglen_t msg_qbytes; //队列所能容纳的最大字节数
pid_t msg_lspid; //上一次使用msgsnd()的进程
pid_t msg_lrpid; //上一次使用msgrcv()的进程
}