前言
本文为笔者学习笔记,若有不妥之处,欢迎斧正。
一、消息队列概述
消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
消息队列的特点:
- 消息队列是面向记录的,其中消息具有特定的格式以及特定的优先级。
- 消息队列独立于发送和接受进程。进程终止时,消息队列的内容并不会被删除。
- 消息队列可以实现消息的随机查询,消息不一定要以先进先出的顺序读取,可以按照消息的类型读取。
进程间通过消息队列通信步骤:
- 创建或打开消息队列
- 添加消息
- 读取消息
- 控制消息队列。
二、消息队列相关API详解
1.获取键值
函数原型:
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
函数作用:生成消息队列的键值(每一个消息队列都有一个对应的键值相关联,共享内存和信号量也需要)。
参数说明:
- pathname:路径名。
- proj_id:是0到25之间的值,可以随意取。
返回值:成功返回键值,失败返回-1。
2.打开或创建消息队列
函数原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
函数作用:创建或者打开消息队列。
参数说明:
- key:ftok函数返回的键值,也就是消息队列的键值。
- msgflg:需要的操作和权限,可以用来创建一个消息队列。
返回值:成功返回队列ID,失败返回-1。
3.添加消息
函数原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
函数作用:添加消息。
参数说明:
- msgid:消息队列ID。
- msgp:消息结构体指针。
- msgsz:结构体中字符数组的大小。(发送可用sizeof或者strlen计算)
- msgflg:可以为0,也可以为IPC_NOWAIT。
返回值:成功返回0,失败返回-1。
4.读取消息
函数原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
函数作用:读取消息队列中的消息。
参数说明:
- msgid:消息队列ID。
- msgp:消息结构体指针。
- msgsz:结构体中字符数组的大小。(使用sizeof计算)
- msgtyp:消息类型。
- 可以为0,也可以为IPC_NOWAIT。
返回值:成功返回消息的数据长度,失败返回-1。
5.控制消息队列
函数原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
函数作用:控制消息队列(实现消息队列的删除和修改)。
参数说明:
- msgid:消息队列ID。
- cmd:控制选项(或控制命令),下面详解
- buf:存放属性信息(控制删除是,设置为NULL即可)
返回值:成功返回0,失败返回0。
cmd选项:
- IPC_STAT:将msqid消息队列的属性信息,读到第三个参数所指定的缓存。
- IPC_SET:使用第三个参数中的新设置去修改消息队列的属性。
- IPC_RMID:删除消息队列,用不到第三个参数,用不到时设置为NULL。
6.消息队列的消息结构体
原型如下:
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
成员说明:
mtype:消息类型。
mtext:消息内容。
三、代码演示
- 进程1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
typedef struct msg
{
long mtype;
char mtext[64];
}MSG,*PMSG;
int main(void)
{
key_t key;
int msgid;
MSG sendBuf={
888,"Good morning.Have you had your meal."};
MSG receiveBuf;
memset(receiveBuf.mtext,'\0',64);
key = ftok(".",'z');
if(key == -1)
{
perror("ftok failed:");
exit(-1);
}
msgid = msgget(key,IPC_CREAT|0777);
if(msgid == -1)
{
perror("msgget failed:");
exit(-1);
}
msgsnd(msgid,&sendBuf,strlen(sendBuf.mtext),0);
printf("send over\n");
msgrcv(msgid,&receiveBuf,sizeof(receiveBuf.mtext),999,0); //读取消息时,要注意大小需要用sizeof来计算
printf("mtype:%ld,from msg context:%s\n",receiveBuf.mtype,receiveBuf.mtext);
msgctl(msgid,IPC_RMID,NULL);
return 0;
}
- 进程2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
typedef struct msg
{
long mtype;
char mtext[64];
}MSG,*PMSG;
int main(void)
{
key_t key;
int msgid;
MSG sendBuf={
999,"I have already eaten.What about you"};
MSG receiveBuf;
memset(receiveBuf.mtext,'\0',64);
key = ftok(".",'z');
if(key == -1)
{
perror("ftok failed:");
exit(-1);
}
msgid = msgget(key,IPC_CREAT|0777);
if(msgid == -1)
{
perror("msgget failed:");
exit(-1);
}
msgsnd(msgid,&sendBuf,strlen(sendBuf.mtext),0);
printf("send over\n");
msgrcv(msgid,&receiveBuf,sizeof(receiveBuf.mtext),888,0); //读取消息时,要注意大小需要用sizeof来计算
printf("mtype:%ld,from msg context:%s\n",receiveBuf.mtype,receiveBuf.mtext);
msgctl(msgid,IPC_RMID,NULL);
return 0;
}
运行结果如下:
send over
mtype:888,from msg context:Good morning.Have you had your meal.
send over
mtype:999,from msg context:I have already eaten.What about you
总结
参考博文:
https://blog.csdn.net/zhaohong_bo/article/details/89552188
参考书籍:
《UNIX环境高级编程》第三版