一 关于消息队列
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法,而且,每个数据块都被认为含有一个类型,接收进程可以独立地接受含有不同类型值的数据块。可以通过发送消息来几乎完全避免命名管道的同步和阻塞问题。但是,与管道一样,每个数据块都有一个最大长度的限制,系统中所有队列所包含的全部数据块的总长度都有一个上限。
与命名管道相比,消息队列的优势是,它独立于发送和接受进程而存在,这消除了在同步命名管道的打开和关闭时可能产生的一些困难。
二 相关函数
#include <sys/msg.h> //msgget函数创建和访问一个消息队列 int msgget(key_t key,
int msgflg //由IPC_CREAT定义的一个特殊位必须和权限标志按位或才能创建一个新的消息队列,在设置IPC_CREAT标志时,如果给出的是一个已有消息队列的键也不会产生错误。如果消息队列已有,则IPC_CREAT标志就被悄悄地忽略掉。
); //成功时msgget函数返回一个正整数,即队列标识符,失败时返回-1
//msgsnd函数用来把消息添加到消息队列中 int msgsnd(int msqid, //是由msgget函数返回的消息队列标识符
const void *msg_ptr, //是一个指向准备发送消息的指针
size_t msg_sz, //是msg_ptr指向的消息的长度,它不包括长整型消息类型成员变量的长度
int msgflg //是控制在当前消息队列满或队列消息到达系统范围的限制时将要发生的事情。
//如果msgflg中设置了IPC_NOWAIT标志,函数将立刻返回,不发送消息并且返回值为-1.如果msgflg中IPC_NOWAIT标志被清除,则发送进程将挂起以等待队列中腾出可用空间。
);
//msgrcv函数从一个消息队列中获取消息
int msgrcv(int msqid, //由msgget函数返回的消息队列标识符
void *msg_ptr, //是一个指向准备接受消息的指针,消息必须以一个长整数型成员变量开始
size_t msg_sz, //是msg_ptr指向的消息的长度,它不包括长整型消息类型成员变量的长度
long int msgtype, //如果值为0,就获取队列中的第一个可用消息;如果它的值大于零,将获取具有相同消息类型的第一个消息;如果它的值小于零,将获取消息类型等于或小于msgtype的绝对值的第一个消息
int msgflg //用于控制当队列中没有相应类型的消息可以接受时将发生的事情
); //成功时msgrcv函数返回放到接收缓存区中的字节数,消息被复制到由msg_ptr指向的用户分配的缓存区中,然后删除消息队列中的对应消息,失败时返回-1
//msgctl函数与共享内存的控制函数相似 int msgctl(int msqid, //是msgget返回的消息队列标识符
int cmd, //将要采取的动作
struct msqid_ds *buf
); //成功时返回0,失败时返回-1,如果删除消息队列时,某个进程正在msgsnd或msgrcv函数中等待,这两个函数将失败
msgctl中第二个参数要采取的动作:
IPC_STAT:把msqid_ds结构中的数据设置为消息队列的当前关联值
IPC_SET:如果进程有足够的权限,就把消息队列的当前关联值设置为msqid_ds结构中给出的值
IPC_RMID:删除消息队列
三 实验
msg1.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.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
",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
",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
");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
msg2.c
#include <stdio.h>
#include <stdlib.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",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
");
exit(EXIT_FAILURE);
}
if(strncmp(buffer,"end",3)==0){
running=0;
}
}
exit(EXIT_FAILURE);
}