1.什么是消息队列?
消息队列是消息的链接表 ,存放在内核中并由消息队列标识符标识。我们将称消息队列为“队列”,其标识符为“队列I D”。
2.函数介绍
2.1msgget函数
1,调用的第一个函数通常是m s g g e t,其功能是打开一个现存队列或创建一个新队列。
2,函数原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int flag) ;
//返回:若成功则为消息队列I D,若出错则为- 1
第一个参数key:0(IPC_PRIVATE):会建立新的消息队列;大于0的32位整数:视参数msgflg来确定操作。通常要求此值来源于ftok返回的IPC键值。
第二个参数flag:0:取消息队列标识符,若不存在则函数会报错;IPC_CREAT:当msgflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的消息队列,则新建一个消息队列;如果存在这样的消息队列,返回此消息队列的标识符IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相等的消息队列,则新建一个消息队列;如果存在这样的消息队列则报错。
2.2msgctl函数
1,msgctl函数对队列执行多种操作。
2,函数原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf)
//返回:若成功则为0,出错则为- 1
第一个参数msqid:消息队列标识符
第二个参数cmd:IPC_STAT:获得msgid的消息队列头数据到buf中IPC_SET:设置消息队列的属性,要设置的属性需先存储在buf中,可设置的属性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes。
2.3msgsnd函数
1,调用msgsnd将数据放到消息队列上。
2,函数原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)
//返回:若成功则为0,若出错则为- 1
第一个参数msqid:消息队列标识符
第二个参数msgp:发送给队列的消息。msgp可以是任何类型的结构体,但第一个字段必须为long类型,即表明此发送消息的类型,msgrcv根据此接收消息。msgp定义的参照格式如下:
struct s_msg
{/*msgp定义的参照格式*/
long type; /* 必须大于0,消息类型 */
char mtext[256]; /*消息正文,可以是其他任何类型*/
} msgp;
第三个参数msgsz:发送消息的大小,不含消息类型占用的4个字节,(mtext长度)
第四个参数msgflg:0:当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列IPC_NOWAIT:当消息队列已满的时候,msgsnd函数不等待立即返回IPC_NOERROR:若发送的消息大于size字节,则把该消息截断,截断部分将被丢弃,且不通知发送进程。
2.4msgrcv函数
1,msgrcv 用于从消息队列读取消息
2,函数原型
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgrcv(int msqid, void * ptr, size_t nbytes, long type, int flag) ;
//返回:若成功则为消息数据部分的长度,若出错则为 - 1
第一个参数msqid:消息队列标识符
第二个参数ptr:存放消息的结构体,结构体类型要与msgsnd函数发送的类型相同
第三个nbytes:要接收消息的大小,不含消息类型占用的4个字节
第四个type:
0:接收第一个消息 > 0:接收类型等于msgtyp的第一个消息
<0:接收类型等于或者小于msgtyp绝对值的第一个消息
第五个flag:0: 阻塞式接收消息,没有该类型的消息msgrcv函数一直阻塞等待
3,msgrcv()解除阻塞的条件有以下三个:
① 消息队列中有了满足条件的消息。
② msqid代表的消息队列被删除。
③ 调用msgrcv()的进程被信号中断。
3.应用实例
1发送端:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#define MAX_TEXT 512
struct msg_struct //表明发送信息的结构体
{
long msg_type;
char msg_text[MAX_TEXT];
}msg_st;
int main()
{
int msgid = -1;
int starting = 1;
long int msgtype = 0;
struct msg_struct data;
char buffer[BUFSIZ];
msgid = msgget((key_t)1234, 0666 | IPC_CREAT); //建立消息队列
if(msgid < 0 )
{
printf("creta msgget failure\n");
return -1;
}
printf("creat msgget successful\n");
while(starting) //输入数据
{
printf("请输入消息:\n");
fgets(buffer, BUFSIZ, stdin);
data.msg_type = 1;
// 向队列发消息
strcpy(data.msg_text, buffer);
if(msgsnd(msgid,(void*)&data,MAX_TEXT , 0) <0 )
{
printf("msgsnd errno :%d\n", errno);
return -2;
}
// 输入end时则结束对话
if(strncmp(buffer, "end", 3) == 0)
starting = 0;
sleep(1);
}
return 0;
}
2接收端:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
struct msg_struct
{
long int msg_type;
char msg_text[BUFSIZ];
}msg_st;
int main()
{
int starting = 1;
int msgid = -1;
struct msg_struct data;
long int msgtype = 0;
//建立消息队列
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if(msgid <0 )
{
printf("msgget failed with error: %d\n", errno);
return -1;
}
//从队列中获取消息,直到遇到end消息为止
while(starting)
{
if(msgrcv(msgid, (void*)&data, BUFSIZ, msgtype, 0) < 0)
{
printf("msgrcv failed with errno: %d\n", errno);
return -2;
}
printf("You wrote: %s\n",data.msg_text);
//遇到end结束
if(strncmp(data.msg_text, "end", 3) == 0)
starting = 0;
}
//删除消息队列
if(msgctl(msgid, IPC_RMID, 0) == -1)
{
printf("msgctl(IPC_RMID) failed\n");
return -3;
}
return 0;
}
3.1结果展示
先分别打开两个程序,首先打开客户端:
然后打开接收端:
在客户端输入信息
直到输入end时 程序终止。