消息队列
1. 消息队列概述
消息队列就是一些消息的列表,用户可以在消息队列中添加消息和读取消息等。消息队列具有一定的FIFO特性,但是它可以实现消息的随机查询,比FIFO具有更大的优势。同时,这些消息优势存在于内核中,由“队列ID”来标识。
2. 消息队列编程
2.1 编程说明
消息队列的实现包括以下4种操作:
- 创建或打开消息队列,使用 msgget() 函数
- 添加消息,使用 msgsnd() 函数
- 读取消息,使用 msgrcv() 函数
- 控制消息队列,使用 msgctl() 函数
2.2 函数介绍
msgget() 函数
/*****msgget()函数*****/
函数原型:int msgget(key_t key, int msgflg)
传 入 值:key 消息队列的键值,多个进程可通过它访问同一个消息队列。IPC_PRIVATE用于创建私有消息队列
msgflg 权限标志位
返 回 值:成功:消息队列ID;
失败:返回-1
msgsnd() 函数
/*****msgsnd()函数*****/
函数原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)
传 入 值:msqid 消息队列的队列ID
msgp 指向消息结构的指针
msgsz 消息正文的字节数
msgflg 若为0表示调用阻塞直到发送成功为止;IPC_NOWAIT表示若消息无法立即发送,函数会立即返回
返 回 值:成功:返回0;失败:返回-1
//消息结构msgbuf的定义
struct msgbuf{
long mtype; //消息类型,该结构必须从这个域开始
char mtext[1]; //消息正文
}
msgrcv() 函数
/*****msgrcv()函数*****/
函数原型:int msgrcv(int msgid, void *msgp, size_t msgsz, long int msgtyp, int msgflg)
传 入 值:msqid 消息队列的队列ID
msgp 指向消息结构的指针,同msgsnd()函数的msgp
msgsz 消息正文的字节数
msgtyp -->为0表示接收消息队列中第一消息;
-->大于0表示接收消息队列中第一个类型为msgtyp的消息;
-->小于0表示接收消息队列中第一个类型值不小于msgtyp绝对值且类型值最小的消息
msgflg -->MSG_NOERROR 若返回的消息比msgsz字节多,则消息就会截短到msgsz字节,且不通知消息发送进程;
-->IPC_NOWAIT 若在消息队列中没有相应类型的消息可以接收,则函数立即返回;
-->0 msgsnd()调用阻塞直到接收一条相应类型的消息位置;
返 回 值:成功:返回0
失败:返回-1
msgctl() 函数
/*****msgctl()函数*****/
函数原型:int msgctl(int msgid, int cmd, struct msqid_ds *buf)
传 入 值:msqid 消息队列的队列ID
cmd -->IPC_STAT 读取消息队列的数据结构msqid_ds,并将其存储在buf指定的地址中;
-->IPC_SET 设置消息队列的数据结构msgid_ds中的ipc_perm域值,这个值取自buf参数;
-->IPC_RMID 从系统内核中删除消息队列;
buf 描述消息队列的msqid_ds结构类型变量
返 回 值:成功:返回0
失败:返回-1
2.3 函数实例
下面的实例体现了如何使用消息队列进行两个进程(发送端和接收端)之间的通讯。消息发送端进程和消息接收端进程间不需要额外实现进程间的同步。
消息对发送端代码如下:
/*****msgsnd.c*****/
//省略头文件
#define BUFFER_SIZE 512
struct message{
long msg_type;
char msg_text[BUFFER_SIZE];
};
int main(){
int qid;
key_t key;
strcut message msg;
if((key = ftok(".",'a')) == -1){
perror("ftok");
exit(1);
}
if((qid = msgget(key, IPC_CREAT|0666)) == -1){
perror("msgget");
exit(1);
}
printf("Open queue %d\n",qid);
while(1){
printf("Enter some message to the queue:");
if((fgets(msg.msg_text,BUFFER_SIZE,stdin)) == NULL){
puts("no message");
exit(1);
}
msg.msg_type = getpid();
if((msgsnd(qid, &msg, strlen(msg.msg_text), 0)) < 0){
perror("message posted");
exit(1);
}
if((strncmp(msg.msg_text, "quit", 4)) == 0)
break;
}
exit(0);
}
消息队列接收端的代码如下:
/*****msgrcv.c*****/
//省略头文件
#define BUFFER_SIZE 512
struct message{
long msg_type;
char msg_text[BUFFER_SIZE];
};
int main(){
int qid;
key_t key;
strcut message msg;
if((key = ftok(".",'a')) == -1){
perror("ftok");
exit(1);
}
if((qid = msgget(key, IPC_CREAT|0666)) == -1){
perror("msgget");
exit(1);
}
printf("Open queue %d\n",qid);
do{
memset(msg.msg_text, 0, BUFFER_SIZE);
if((msgrcv(qid, (void *)&msg, BUFFER_SIZE, 0, 0)) < 0){
perror("msgrcv");
exit(1);
}
printf("The message from process %d : %s",msg.msg_type,msg_msg_text);
}while(strncmp(msg.msg_text, "quit", 4));
if((msgctl(qid, IPC_RMID, NULL)) < 0){
perror("msgctl");
exit(1);
}
exit(0);
}