消息队列:两个不相关的进程中进行通讯
“消息队列”是一个存放在内核的队列,是在消息的传输过程中保存消息的容器。因为它消息队列保存在内核中,所以我们必须显示地删除一个消息队列。否则这个消息队列会一直存在于内核找到操作系统重启(内核重启)。
消息队列中传递的消息是一个包含消息类型的结构体(数据块),进程可以根据消息类型独立的接收含有不同类型值的数据块。
消息队列保存消息,它独立于发送和接收进程而存在,使得读端可以在写端离线的情况下工作,也不需要做同步控制。
消息的结构:
struct message
{
long message_type;
… //具体的消息载体
}
消息队列的操作函数:#include<sys/msg.h>
①创建消息队列
int msgget(key_t key, int glag); //成功,返回消息队列标识符;失败返回-1
key:键值,用来命名特定的消息队列。用户可以自主给定;特殊键值IPC_PRIVATE用于创建私有队列,只能被当前进程访问(没有什么用处)。
msgflg:创建消息队列的权限 和 标志。创建时指定标志为IPC_CREAT。
②发送消息,将消息添加到消息队列中,总是添加到队列的尾端,调用成功时消息数据的副本将被放到消息队列中。
int msgsnd(int msgid, const void *ptr, size_t size, int flag); //失败返回-1
msgid:消息队列标识符
ptr:指向要添加的消息的指针
size:消息实际内容的大小,不包括消息类型
flag:用来指定该操作失败(当前队列满 或 消息队列达到系统返回的限制)时的动作。如果设为IPC_NOWAIT,则函数立刻返回不发送消息且返回-1。一般设为0,将进程挂起,直到有队列中有空间可用。
③从消息队列中获取消息:
int msgrcv(int msgid, void *msg_ptr, size_t size, long int msgtype, int msgflg);
该函数与msgsnd的参数意义基本相同。第四个参数msgtypes指定要获取的消息类型。0:获取消息队列中第一个可用的消息;>0:获取具有相同消息类型的第一个消息;<0:获取消息类型等于或小于msgtype的绝对值的第一个消息
成功时返回放到接收缓存区中的字节数,消息被复制到msg_ptr指向的消息结构中,然后删除消息队列中的对应消息。失败返回-1。
④操作消息队列,可用于删除消息队列:
int msgctl(int msgid, int commed, struct msgid_ds *buf); //成功0,失败-1
commed:IPC_RMID 删除消息队列
IPC_STAT 取此队列的msgid_ds,并存放到buf指定的结构中
IPC_SET 把消息队列的当前关联值设为buf指向结构体的值
下面给一个具体的例子:
写端:msgwrite.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/msg.h>
#define MESSIZE 128
//消息的结构
struct my_message
{
long int message_type; //消息类型
char text[MESSIZE]; //消息内容
};
int main()
{
//创建一个消息队列
int msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
struct my_message message;
message.message_type = 2;
while(1)
{
char buff[128] = {0};
printf("put in:");
fgets(buff,127,stdin);
strcpy(message.text,buff);
//把消息添加到消息队列中
if(msgsnd(msgid,(void*)&message,MESSIZE,0) == -1)
{
printf("mshsnd failed\n");
exit(1);
}
if(strncmp(buff,"end",3) == 0)
{
break;
}
}
}
读端:msgread.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/msg.h>
#define MESSIZE 128
//消息的结构
struct my_message
{
long int message_type; //消息类型
char text[MESSIZE]; //消息内容
};
int main()
{
//创建一个消息队列
int msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
struct my_message message;
while(1)
{
//从消息队列中读取消息
if(msgrcv(msgid,(void*)&message,MESSIZE,2,0) == -1)
{
printf("msgrcv failed\n");
exit(1);
}
printf("you wrote:%s",message.text);
if(strncmp(message.text,"end",3) == 0)
{
break;
}
}
//删除消息队列
if(msgctl(msgid,IPC_RMID,NULL) == -1)
{
fprintf(stderr,"msgctl(IPC_RMID) failed\n");
exit(1);
}
}