消息队列提供了一种在两个不相关的进程之间传递数据的相当简单且有效的方法。与命名管道相比,消息队列的优势在于,它独立于发送和接收进程而存在,这消除了在同步命名管道的打开和关闭时可能产生的一些困难。
我们可以通过发送消息来几乎完全避免命名管道的同步和阻塞问题。
但是与管道一样,每个数据块都有一个最大限度的长度限制。
消息队列的函数:
#include <sys/msg.h>
int msgctl(int msqid,int cmd,struct msqid_ds *buf);
int msgget(key_t key,int msgflg); 创建和访问一个消息队列
int msgrcv(int msqid,void *msg_ptr,size_t msg_sz,long int msgtype,int msgflg);从一个消息队列中获取消息
int msgsnd(int msqid,const void *msg_ptr,size_t msg_sz,int msgflg);把消息添加到消息队列中
msg1.c
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<unistd.h>
#include<sys/msg.h>
struct my_msg_st{
long int my_msg_type;
char some_text[BUFSIZ];
};
int main()
{
int running=1;
int msgid;
struct my_msg_st some_data;
long int msg_to_receive=0;
//建立消息队列
msgid=msgget((key_t)1234,0666|IPC_CREAT);
if(msgid==-1)
{
fprintf(stderr,"msgget failed with error: %d\n",errno);
exit(EXIT_FAILURE);
}
//从队列中获取消息,直到遇见end为止
while(running)
{
if(msgrcv(msgid,(void *)&some_data,BUFSIZ,msg_to_receive,0)==-1)
{
fprintf(stderr,"msgrcv failed with error: %d\n",errno);
exit(EXIT_FAILURE);
}
printf("You wrote: %s",some_data.some_text);
if(strncmp(some_data.some_text,"end",3)==0)
running=0;
}
if(msgctl(msgid,IPC_RMID,0)==-1)
{
fprintf(stderr,"msgctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
msg2.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/msg.h>
#define MAX_TEXT 512
struct my_msg_st{
long int my_msg_type;
char some_text[MAX_TEXT];
};
int main()
{
int running=1;
struct my_msg_st some_data;
int msgid;
char buffer[BUFSIZ];
msgid=msgget((key_t)1234,0666|IPC_CREAT);
if(msgid==-1)
{
fprintf(stderr,"msgget failed with error: %d\n",errno);
exit(EXIT_FAILURE);
}
while(running)
{
printf("Enter some text: ");
fgets(buffer,BUFSIZ,stdin);
some_data.my_msg_type=1;
strcpy(some_data.some_text,buffer);
if(msgsnd(msgid,(void *)&some_data,MAX_TEXT,0)==-1)
{
fprintf(stderr,"msgsnd failed\n");
exit(EXIT_FAILURE);
}
if(strncmp(buffer,"end",3)==0)
running=0;
}
exit(EXIT_SUCCESS);
}
与管道不同,这里不再需要由进程自己来提供同步方法,这是消息队列相对于管道的一个明显优点。
发送者程序通过msgget来创建一个消息队列,然后用msgsnd向队列中增加消息。接收者用msgget获得消息队列标识符,然后开始接收消息,直到接收到特殊的文本end为止。然后用msgctl来删除消息队列以完成清理工作。