一、什么是消息队列?
消息队列与命名管道相似,提供了从一个进程向另外一个进程发送数据块的方法,接收进程可以独立,有选择的接收含有不同类型的数据块,由内核实现。
二、消息队列的操作
1. 创建或获取:Int msgget((key_t)key, int flag);
Key是键值,是一个唯一的非零整数,类似于一个“身份证号”,其它进程通过这个“身份证号”来使用对应的消息队列;
Flag 用来确定操作和权限,可以通过与上PC_CREAT在不存在该信号量时创建,存在时获取;
返回值:非零的消息队列的标识符,其它函数根据标识符来操作,而非键值;
栗子:int msg_id = msgget( (key_t)1234, 1, 0666|IPC_CREAT );
2. 发送消息:int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);
msgid是由msgget函数返回的消息队列标识符
msg_ptr是指向准备发送的消息,消息的数据结构有一定的要求,指针msg_ptr所指向的消息结构一定要是以一个整型
成员变量开始的结构体,接收函数将用这个成员来确定消息的类型。
消息的数据结构一般为:
struct msg_buff
{
long type;
char data[128];
};
msg_sz是msg_ptr指向的消息的长度,不是整个结构体的长度,不包括消息类型成员变量的长度
msgflg用于控制当前消息队列满或队列消息到达系统范围的限制时将要发生的事情。
如果调用成功,消息数据的一分副本将被放到消息队列中,并返回0,失败时返回-1.
3. 接收消息:int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);
msgtype用来选择接收的消息类型,可以实现一种简单的接收优先级
msgtype=0,就获取队列中的第一个消息
msgtype>0,将获取具有相同消息类型的第一个信息
msgtype<0,就获取类型等于或小于msgtype的绝对值的第一个消息
然后删除消息队列中的对应消息。失败时返回-1
4.删除消息队列:int msgctl(int msgid, int command, struct msgid_ds *buf);
command是将要采取的动作,它可以取3个值,
IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值
IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值
IPC_RMID:删除消息队列
成功时返回0,失败时返回-1.
栗子:msgctl(msgid, IPC_RMID, 0);
三、实例:进程A发送b和c俩种类型的数据,进程B根据调用参数选择接收b或者c类型的数据
msga.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct msg_buff
{
long type;
char data[128];
};
void main()
{
int msgid = msgget( (key_t)1234,IPC_CREAT|0666);
assert(msgid != -1);
struct msg_buff buff;
char buffer[128];
while(1)
{
printf("A->B:");
fgets(buffer,128,stdin);
if(strncmp(buffer,"end",3)==0)
{
break;
}
buff.type = 1000;
strcpy(buff.data,buffer);
if( msgsnd(msgid,&buff,strlen(buff.data),0) == -1)
{
printf("msgsnd A->B error\n");
exit(0);
}
printf("A->C:");
fgets(buffer,128,stdin);
if(strncmp(buffer,"end",3)==0)
{
break;
}
buff.type = 2000;
strcpy(buff.data,buffer);
if( msgsnd(msgid,&buff,strlen(buff.data),0) == -1)
{
printf("msgsnd A->C error\n");
exit(0);
}
}
strcpy(buff.data,"end");
buff.type = 1000;
if( msgsnd(msgid,&buff,strlen(buff.data),0) == -1)
{
printf("B msgsnd end error\n");
exit(0);
}
buff.type = 2000;
if( msgsnd(msgid,&buff,strlen(buff.data),0) == -1)
{
printf("C msgsnd end error\n");
exit(0);
}
}
msgb:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct msg_buff
{
long type;
char data[128];
};
void main(int argc,char *argv[])
{
if(argc <2)
{
printf("argc error\n");
return ;
}
int msgid = msgget( (key_t)1234,IPC_CREAT|0666);
assert(msgid != -1);
struct msg_buff buff;
memset(&buff,0,sizeof(buff));
int msgtype = 0;
if(strncmp(argv[1],"B",1)==0)
{
msgtype= 1000;
}else if(strncmp(argv[1],"C",1)==0)
{
msgtype = 2000;
}
while(1)
{
if( msgrcv(msgid,(void *)&buff,127,msgtype,0) == -1)
{
printf("msgrcv error\n");
exit(0);
}
if(strncmp(buff.data,"end",3)==0)
{
break;
}
buff.data[strlen(buff.data)-1]='\0';
printf("You wrote: %s\n",buff.data);
}
if(msgctl(msgid, IPC_RMID, 0) == -1)
{
printf("msgctl error\n");
exit(0);
}
}
运行结果: