消息队列
消息:由数据 && 类型 组成
队列:学过数据结构我们知道,队列的特点是先进先出。
消息队列:是种临时存储消息的队列,完成进程间数据传送,可以按照队列的特点和消息的类型优先传送数据。
特点:
(1)与信号量相比,都以内核对象来确保多进程访问同一个消息队列,信号量控制进程间同步,而消息队列发送数据。
(2)与管道相比,管道发送的数据没有类型,读取数据端 无差别从管道中按照数据的前后顺序读取数据,消息队列的数据有类型,读端可以通过消息队列的类型读取特定的数据。
消息队列的创建或获取:
1 、
#include<sys/msg.h>
int msgget(key_t key,int flag)
key_t key 为键值,用户可以随意给一个long类型,然后转成key_t。
flag 权限加 标志,创建消息队列时,指定IPC_CREATE,不用向信号量那样必须初始化,因为消息队列本身就带有消息的信息。成功返回消息队列ID msgid,失败返回-1.
2、发送消息,将消息放到消息队列中,消息总是放在队列尾端。
int msgsnd(int msgid, const void*ptr,size,int flag)
msgid就是消息队列ID
ptr就是指向mymesg结构体的指针,也就是指向消息的指针
size就是消息实际内容的字节数,也就是mymesg的第二个成员。
flag 用来控制一些特殊的操作,比如flag可以设为IPC_NOWAIT,指明消息队列没有足够的空间容纳要发送的消息时,msgsnd是否等待。一般我们设为0就好了。
int msgget(key_t key,int flag)
key_t key 为键值,用户可以随意给一个long类型,然后转成key_t。
flag 权限加 标志,创建消息队列时,指定IPC_CREATE,不用向信号量那样必须初始化,因为消息队列本身就带有消息的信息。成功返回消息队列ID msgid,失败返回-1.
2、发送消息,将消息放到消息队列中,消息总是放在队列尾端。
int msgsnd(int msgid, const void*ptr,size,int flag)
msgid就是消息队列ID
ptr就是指向mymesg结构体的指针,也就是指向消息的指针
size就是消息实际内容的字节数,也就是mymesg的第二个成员。
flag 用来控制一些特殊的操作,比如flag可以设为IPC_NOWAIT,指明消息队列没有足够的空间容纳要发送的消息时,msgsnd是否等待。一般我们设为0就好了。
3、
int msgrcv(int msgid,struct mymesg_ds *buf,int size,long type,int flag)
第一个参数就不多说了,第二个参数系统内核为每一个队列的当前状态设了相关联的结构体。
size就是消息实际内容的字节数,也就是mymesg的第二个成员。
long type 这个参数重要了,当你想获取1000这个类型的消息,就会优先读取1000这个类型消息的内容。
flag参数同上个函数是一样的
第一个参数就不多说了,第二个参数系统内核为每一个队列的当前状态设了相关联的结构体。
size就是消息实际内容的字节数,也就是mymesg的第二个成员。
long type 这个参数重要了,当你想获取1000这个类型的消息,就会优先读取1000这个类型消息的内容。
flag参数同上个函数是一样的
4、
int msgctl(int msgid ,int cmd,struct msgid_ds *buf)
cmd参数:如果你想删除消息,cmd为IPC_RMID,最后一个参数设为0就好了。
还有两个cmd参数:IPC_STAT取此队列的msgid_ds,并存放在buf指向的结构中
IPC_SET 按由buf指向结构体中的值,设置与此队列相关结构体的成员。
我们看个例子,就知道消息队列到底是怎么传送数据的。
A进程负责根据用户选择的数据类型(long)发送,用户输入的数据(char*)
B进程读取1000类型的数据
C进程读取2000类型的数据
cmd参数:如果你想删除消息,cmd为IPC_RMID,最后一个参数设为0就好了。
还有两个cmd参数:IPC_STAT取此队列的msgid_ds,并存放在buf指向的结构中
IPC_SET 按由buf指向结构体中的值,设置与此队列相关结构体的成员。
我们看个例子,就知道消息队列到底是怎么传送数据的。
A进程负责根据用户选择的数据类型(long)发送,用户输入的数据(char*)
B进程读取1000类型的数据
C进程读取2000类型的数据
我们利用main函数可以传参把B、C进程写成一个程序。
A进程:
#include<stdio.h>
#include<assert.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/msg.h>
#include<sys/ipc.h>
#include<sys/types.h>
struct mymesg
{
long type;
char mtext[512];
}mymesg;
int main()
{
int msgid=msgget((key_t)1234,0664|IPC_CREAT);
assert(msgid!=-1);
struct mymesg ptr;ptr.type=1000;
ptr.mtext[512];
strcpy(ptr.mtext,"hello");
if(msgsnd(msgid,&ptr,512,IPC_NOWAIT)==-1)
{
perror("error\n");
exit(0);
}
ptr.type=2000;
strcpy(ptr.mtext,"world");
if(msgsnd(msgid,&ptr,512,IPC_NOWAIT)==-1)
{
perror("error");
exit(0);
}
}
B、C进程
#include<stdio.h>
#include<assert.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/msg.h>
#include<sys/ipc.h>
#include<sys/types.h>
struct mymesg
{
long type;
char mtext[512];
};
int main(int argc,char*argv[])
{
char buff[128]={0};
struct mymesg ptr;
int msgid=msgget((key_t)1234,0664|IPC_CREAT);
assert(msgid!=-1);
if(argc<=1)
{
perror("few option\n");
exit(0);
}
sscanf(argv[1],"%d",&ptr.type);
if(msgrcv(msgid,&ptr,512,ptr.type,0)!=-1)
{
printf("%s\n",ptr.mtext);
}
/*if(msgctl(msgid,IPC_RMID,0)==-1)
{
perror("error\n");
exit(0);
}等读完消息队列的数据,再删了消息队列,否则只能读一次哦*/
}
运行结果: