消息队列:
基本特点:是由内核负责维护管理的链式数据队列,不是根据先后顺序出队,而是根据消息类型进行收发数据
int msgget(key_t key, int msgflg);
功能:创建\获取消息队列
key:IPC键值
msgflg:
IPC_CREAT 消息队列已存在则获取,否则创建
IPC_EXCL 消息队列已存在则返回错误
注意:如果创建需要提供权限
返回值:IPC标识符,失败-1
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:向消息队列发送消息包
msqid:IPC标识符
msgp:要发送的消息包的首地址
struct msgbuf {
long mtype; // 消息类型
char mtext[n]; // 数据
...
};
msgsz:数据的字节数,不包含消息类型
msgflg:
阻塞发送一般给0
IPC_NOWAIT 当消息队列满,不等待立即返回
返回值:成功返回0,失败返回-1
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
功能:从消息队列中接收对应消息包的数据
msqid:IPC标识符
msgp:存储消息包的内存首地址
msgsz:存储数据的内存字节数(尽量大些)
msgtyp:消息类型(按照类型获取,不按照顺序)
>0 读取消息类型=msgtyp的消息
=0 读取消息队列中第一条消息
<0 读取消息类型小于abs(msgtyp)的消息,如果有多个则读值最小的
msgflg
IPC_NOWAIT 消息队列都不符合时不阻塞,立即返回
MSG_EXCEPT 如果msgtyp>0,则读取第一条不等于msgtyp的消息
MSG_NOERROR 如果不包含此标志,如果实际发送过来的数据字节数>接收的字节数,则返回失败,如果包含此标志,那么就只读取接收的字节数,一定会成功
返回值:成功读取到数据的字节数
int msgctl(int msqid,int cmd,struct msqid_ds *buf);
功能:获取\修改消息队列的属性、删除队列
msqid:IPC标识符
cmd:
IPC_STAT 获取消息队列属性 buf输出型参数
IPC_SET 设置消息队列属性 buf输入型参数
IPC_RMID 删除消息队列 NULL
buf
编程模型:
进程A 进程B
创建消息队列 获取消息队列
发送消息 获取消息
获取消息 发送消息
删除消息队列
1.先定义一个message.h存放结构体
使用头文件卫士
#pragma once
#define MAXMSG 256
typedef struct msgbuf
{
long type;
char data[MAXMSG];
}Msg;
2.进程A
message.c
#include <stdio.h>
#include<sys/types.h>
#include<sys/msg.h>
#include<sys/ipc.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include "message.h"
int main(int argc,const char* argv[])
{
//创建消息队列
int msgid=msgget(ftok(".",120), IPC_CREAT|0644 );
if(msgid<0)
{
perror("msgget");
return -1;
}
Msg msg={};
for(;;)
{
msg.type=5;
printf(">>>>>");
scanf("%s",msg.data);
//发送
if(msgsnd(msgid,&msg,strlen(msg.data)+1,0))
{
perror("msgsnd");
return -1;
}
if(0==strcmp("quit",msg.data)) break;//输入quit主动结束
//接受数据
if(0==msgrcv(msgid,&msg,MAXMSG,6,0))
{
perror("msgrcv");
break;
}
printf("recv:%s\n",msg.data);
if(0==strcmp("quit",msg.data)) break;
}
printf("通信结束\n");
sleep(1);
//删除消息队列
if(msgctl(msgid,IPC_RMID,NULL))
{
perror("msgctl");
}
return 0;
}
3.进程B
messageB.c
#include <stdio.h>
#include<sys/types.h>
#include<sys/msg.h>
#include<sys/ipc.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include"message.h"
int main(int argc,const char* argv[])
{
//创建消息队列
int msgid=msgget(ftok(".",120), 0);
if(msgid<0)
{
perror("msgget");
return -1;
}
Msg msg={};
for(;;)
{
//接受数据
if(0==msgrcv(msgid,&msg,MAXMSG,5,0))
{
perror("msgrcv");
break;
}
printf("recv:%s\n",msg.data);
if(0==strcmp("quit",msg.data)) break;//被动结束
msg.type=6;
printf(">>>");
scanf("%s",msg.data);
//发送
if(msgsnd(msgid,&msg,strlen(msg.data)+1,0))
{
perror("msgsnd");
return -1;
}
if(0==strcmp("quit",msg.data)) break;
}
printf("通信结束\n");
sleep(1);
/*//删除消息队列
if(msgctl(msgid,IPC_RMID,NULL))
{
perror("msgctl");
}*/
return 0;
}
主动结束,被动结束
测试结果