1.消息队列的定义
消息队列提供了⼀种从⼀个进程向另⼀个进程发送⼀个数据块的⽅法。 每个数据块都被认为是有⼀个类型,接收者进程接收的数据块可以有不同的类型值。
消息队列接收发送消息的特点:新添加的消息总是在队尾,但接收消息的进程可以读取队列中间的数据。 此外, 消息队列也降低了读写进程间的耦合强度:若接收消息的进程没有接收到消息,发送消息的进程无须等待,可以继续发送消息,消息的读写双方只需关注各自功能的实现情况即可。
消息队列与FIFO(命名管道)的区别:
- 消息队列是基于消息的,⽽管道是基于字节流的,且消息队列的读取不⼀定是先⼊先出。
- 消息队列和管道都可以实现无亲缘关系进程间的通信,且独立于通信双方的进程之外。
- 消息队列的生命周期随内核,而管道的生命周期随进程。
- 消息队列存储的消息和在内核可创建的消息队列个数是有上线的。
2.消息队列的使用及其相关函数
(1)使用消息队列实现进程间通信的步骤
1. 创建消息队列。
2. 发送消息到消息队列。
3. 从消息队列中读取数据
4. 删除消息队列。
(2)消息队列的相关函数。
int msgget(key_t key,int msgflg);
功能:创建一个消息队列或者获取一个已经存在的消息队列.
参数介绍:参数key,表示消息队列的键值,通常为一个整数;参数msgflg,用于设置消息队列的创建方式或者权限,它通常由一个9位的权限与以下值进行位操作后获得的:
a) 当 msgflg=mask|IPC_CREAT 时,若内核中不存在指定消息队列,该函数
会创建一个消息队列;若内核中已存在指定消息队列,则获取该消息队
列;
b) 当 msgflg= mask|IPC_CREAT|IPC_EXCL 时,消息队列不存在时会被创
返回值:成功返回消息队列的标识符,否则返回-1
int msgsnd(int msqid,const void* msgp,size_t msgsz,int msgflg)
功能:向指定消息队列发送一个消息。
参数介绍:参数mspid表示消息队列标识符;参数msgp表示消息缓存区的指针;参数msgsz表示消息中数据的长度,这个长度不包括长整型成员的变量的长度;参数msgflg为标志位,可设置为0或IPC_NOWAIT。
msgsnd()函数发送的消息受两个约束,一消息长度必须小于系统规定上限;二是必须以一个长整形成员变量开始
struct msgbuf{
long int msgtype; //消息类型
anytype dat //要发送的数据,可以为任意类型
返回值:成功返回消息队列标识符,否则返回-1
ssize_t msgrcv(int msqid,void* msgp,size_t msgsz,int msgflg)
功能:从消息队列读取消息,被读取的消息会从消息队列中消失。
参数介绍:参数msqid表示消息队列的id号,通常由 msgset()函数返回;参数 msgp 为指向所读取消息的结构体指针; msgsz 表示消息的长度,这个长度不包含整型成员变量的长度;参数 mtype 表示从消息队列中读取的消息类型,其取值以及各值代表的含义分别如下:
<1>mtype=0,表示获取队列中的第一个可用消息;
<2>mtype>0,表示获取队列中与该值类型相同的第一个消息;
<3> mtype<0,表示获取队列中消息类型小于或等于其绝对值的第一个消息。
最后一个参数 msgflg 依然为标志位, msgflg 设置为 0 时,进程将阻塞等待消息的读取; msgflg 设置为 IPC_NOWAIT 时,进程未读取到指定消息时将立刻返回-1
返回值:成功返回标识符,否则返回-1.
int msgctl(int msqid,int cmd,struct msqid_ds *buf);
功能:对消息队列进行控制。
参数介绍:参数msqid为消息队列的id,后面两个参数我们不关心,通常设置为0,NULL;
返回值:成功返回消息队列标识符,否则返回-1
3消息队列通信代码
//接收者
#include<stdio.h>
#include<stdlib.h>
#include<sys/msg.h>
#include<string.h>
#include<unistd.h>
#define MAX_TEXT 1024
#define MSG_SIZE 512
struct msg_st{
long int msg_type; //消息类型
char text[MAX_TEXT];//消息内容
};
int main()
{
struct msg_st data;
char buf[MSG_SIZE];
int msgid=msgget((key_t)2456,0666|IPC_CREAT);
if(msgid==-1){
perror("msgget");
exit(1);
}
while(1){
printf("接收:");
if(msgrcv(msgid,(void*)&data,MAX_TEXT,1,0)==-1){
perror("msgrcv");
exit(2);
}
printf("%s\n",data.text);
}
return 0;
}
//发送者
#include<stdio.h>
#include<sys/ipc.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/msg.h>
#include<unistd.h>
#include<string.h>
#define MAX_TEXT 512
#define MSG_SIZE 512
struct msg_st
{
long int msg_type; //消息类型
char text[MAX_TEXT];//消息内容
};
int main()
{
struct msg_st data;
char buf[MSG_SIZE];
//创建消息队列
int msgid=msgget((key_t)2456,0666|IPC_CREAT);
if(msgid==-1)
{
perror("msgget");
exit(1);
}
printf("消息队列创建成功\n");
//发送消息
while(1)
{
//从键盘输入发送的消息
printf("发送:");
fgets(buf,MSG_SIZE,stdin);
data.msg_type=1;
strcpy(data.text,buf);
//将消息发送到消息队列
if(msgsnd(msgid,(void*)&data,MAX_TEXT,0)==-1){
perror("msgsnd");
exit(1);
}
}
return 0;
}
发送者展示
接收者展示
我们可以通过ipcs -q 来查看的消息队列
还可以通过ipcrm -q id来删除创建的消息队列