1. 消息队列
1)消息队列由消息队列ID来唯一标识。
2)消息队列就是一个消息的列表。用户可以在消息队列中添加消息、读取消息等。
3)消息队列可以按照类型来发送/接收消息。
4)消息队列的操作包括创建或打开消息队列、添加消息、读取消息和控制消息队列。
5)创建或打开消息队列使用的函数是msgget,这里创建的消息队列的数量会受到系统消息队列数量的限制。
6) 添加消息使用的函数msgsnd,按照类型把消息添加到已打开的消息队列末尾。
7)读取消息使用的函数是msgrcv,可以按照类型把消息从消息队列中取走。
8)控制消息队列使用的函数msgctl
2. 消息队列结构
3. 消息队列编程
使用消息队列通常需要创建/打开消息队列、添加消息、读取消息、控制消息队列四种操作。
1)创建/打开消息队列
函数msgget()
头文件:#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
函数原型:int msgget(key_t key,int msgflg)
函数参数:key 消息队列的键值,其他进程通过该值访问该消息队列,其中有个特殊值IPC_PRIVATE,表示创建当前进程的私有消息队列
msgflg 同open()函数的第三个参数,为消息队列设定权限,通常使用八进制表示。
函数返回值:成功:消息队列ID
失败:-1
2)向消息队列的末尾添加消息
函数msgsnd()
头文件:#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
函数原型:int msgsnd(int msqid, const void*msgp, size_t msgsz, int msgflg)
函数参数:msqid 消息队列标识符(即msgget()函数的返回值)
msgp 指向消息队列的结构体指针,必须使用地址传递的方式传参。该结构体的常用类型如下:
structmsgbuf
{
longmtype;//消息类型,必须大于0
charmtext[n];//消息正文
};
msgsz 消息正文的字节数,必须与第二个参数的消息正文数据长度一致
msgflg
IPC_NOWAIT 若消息无法立即发送则立即返回
0 若消息无法立即发送则阻塞等待消息发送成功
函数返回值:成功:0
失败:-1
3)读取消息队列
函数msgrcv()
头文件:#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
函数原型:ssize_t msgrcv(int msqid, const void*msgp, size_t msgsz, long msgtyp, int msgflg)
函数参数:
msqid 消息队列标识符(即msgget()函数的返回值)
msgp 指向消息队列的结构体指针,必须使用地址传递的方式传参。该结构体的类型同上
msgsz 消息正文的字节数,必须与第二个参数的消息正文数据长度一致
msgtyp
0 接收消息队列中第一个消息
大于0 接收消息队列中第一个值为msgtyp的消息
小于0 接收消息队列中具有小于或等于msgtyp绝对值的最小mtype值的第一条消息
msgflg
MSG_NOERROR 若返回的消息比msgsz字节多,则消息会截断到msgsz字节,且不通知消息发送进程
IPC_NOWAIT 若消息队列中无对应类型的消息接收则立即返回
0 阻塞等待直至接收到一条相应类型的消息为止
函数返回值:
成功:0
失败:-1
4)控制消息队列包括获得属性、删除消息队列等
函数msgctl()
头文件:#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
函数原型:int msgctl(int msqid, int cmd, structmsqid_ds *buf)
函数参数:
msqid 消息队列标识符(即msgget()函数的返回值)
cmd 需要对消息队列采取的操作。可取值有很多,
常用的有:
IPC_STAT 读取消息队列的数据结构msqid_ds并将其存储在buf指定的地址中
IPC_SET 设置消息队列中的数据结构msqid_ds中的pic_perm元素的值。这个值来自buf参数
IPC_RMID 从内核中删除消息队列
buf 该参数是一个msqid_ds类型的结构体指针,使用时必须使用地址传递的方式。结构体成员很多,常用的有:
structmsqid_ds
{
uid_tmsg_perm.uid; /* Effective UID of owner*/
gid_tmsg_perm.gid; /* Effective GID of owner*/
……
};
函数返回值:
成功:0
失败:-1
示例代码分为两个文件,写消息队列和读消息队列。
文件一,写消息队列代码:
/*************************************************************************
@Author: wanghao
@Created Time : Wed 23 May 2018 06:06:21 AMPDT
@File Name: msg_snd_demo.c
@Description:
************************************************************************/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
typedef struct{
longtype;
intstart;
intend;
}MSG;
int main(int argc,char *argv[])
{
if(argc <2){
printf("usage:%s key\n",argv[0]);
exit(1);
}
key_tkey = atoi(argv[1]);
printf("key:%d\n",key);
intmsq_id;
if((msq_id= msgget(key,IPC_CREAT|IPC_EXCL|0777))<0){
perror("msggeterror");
}
printf("msqid: %d\n",msq_id);
MSG m1 = {4,4,400};
MSGm2 = {2,2,200};
MSG m3 = {1,1,100};
MSG m4 = {6,6,600};
MSGm5 = {6,60,6000};
if(msgsnd(msq_id,&m1,sizeof(MSG)-sizeof(long),IPC_NOWAIT)<0){
perror("msgsnderror");
}
if(msgsnd(msq_id,&m2,sizeof(MSG)-sizeof(long),IPC_NOWAIT)<0){
perror("msgsnderror");
}
if(msgsnd(msq_id,&m3,sizeof(MSG)-sizeof(long),IPC_NOWAIT)<0){
perror("msgsnderror");
}
if(msgsnd(msq_id,&m4,sizeof(MSG)-sizeof(long),IPC_NOWAIT)<0){
perror("msgsnderror");
}
if(msgsnd(msq_id,&m5,sizeof(MSG)-sizeof(long),IPC_NOWAIT)<0){
perror("msgsnderror");
}
structmsqid_ds ds;
if(msgctl(msq_id,IPC_STAT,&ds)< 0){
perror("msgctlerror");
}
printf("msgtotal: %ld\n",ds.msg_qnum);
exit(0);
}
文件二,读取消息队列代码:
/*************************************************************************
@Author: wanghao
@Created Time : Wed 23 May 2018 06:03:25 AMPDT
@File Name: msg_rcv_demo.c
@Description:
************************************************************************/
#include <sys/msg.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct{
longtype;
intstart;
intend;
}MSG;
int main(int argc, char *argv[])
{
if(argc< 3){
printf("usage:%s key type\n",argv[0]);
exit(1);
}
key_tkey = atoi(argv[1]);
longtype = atoi(argv[2]);
intmsq_id;
if((msq_id= msgget(key,0777)) < 0){
perror("msggeterror");
}
printf("msgid: %d\n",msq_id);
MSGm;
if(msgrcv(msq_id,&m,sizeof(MSG)-sizeof(long),type,IPC_NOWAIT)<0){
perror("msgrcverror");
}else{
printf("type:%ld start: %d end: %d\n",m.type,m.start,m.end);
}
structmsqid_ds ds;
if(msgctl(msq_id,IPC_STAT,&ds)< 0){
perror("msgctlerror");
}
if(ds.msg_qnum== 0)
{
msgctl(msq_id,IPC_RMID, NULL);
}
exit(0);
}