cpp
复制代码
#include <iostream>
#include<string.h>
#include<unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
using namespace std;
/*
消息队列就是一个消息的列表,用户可以在消息队列中添加消息、读取消息等.
消息队列的使用包括如下4步骤:
1.创建或打开消息队列
int msgget(key_t key, int flag);
key : IPC_PRIVATE(每次用IPC_PRIVATE操作时,共享内存的key都一样,都是0)或ftok的返回值,只要key值是一样的,通过这个函数打开,则会对内核的同一个IPC对象操作
flag:
同open函数的权限位,也可以用8进制表法,IPC_CREA|0666
IPC_CREAT:不存在时创建,存在时返回标识符
IPC_CREAT|IPC_EXCL:确保创建新区段,已存在则失败
成功 :消息队列ID
出错 :-1
2.添加消息
int msgsnd(int msqid, const void *msgp, size_t size, int flag);
msqid:消息队列的ID
msgp:指向消息的指针。常用消息结构
struct msgbuf{
long mtype; //消息类型
char mtext[N]}; //消息正文
}
size:发送的消息正文mtext的字节数
flag:
IPC_NOWAIT,非阻塞添加消息,如果队列满了,直接返回
0:阻塞方式添加消息,如果队列满了,就阻塞,直到消息添加成功
成功:0
出错:-1
3.读取消息
int msgrcv(int msgid, void* msgp, size_t size, long msgtype, int flag);
msqid:消息队列的ID
msgp:接收消息的缓冲区
size:要接收的消息的字节数
msgtype:
0:接收消息队列中第一个消息。
大于0:接收消息队列中第一个类型为msgtyp的消息
小于0:接收消息队列中类型值不大于msgtyp的绝对值且类型值又最小的消息
flag:
0:若无消息函数会一直阻塞
NOWAIT:若没有消息,进程会立即返回ENOMSG
成功:接收到的消息正文的长度
出错:-1
4.控制消息队列
int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );
msqid:消息队列的ID
cmd:
IPC_STAT:读取消息队列的属性,并将其保存在buf指向的缓冲区中。
IPC_SET :设置消息队列的属性。这个值取自buf参数。
IPC_RMID:从系统中删除消息队列,此cmd时第三个参数buf可为NULL
buf : 消息队列缓冲区
成功:0
出错:-1
notice:
1.多个进程同时访问消息队列时会产生竞态状态,必须使用信号量等同步机制来保证操作互斥
ipcs 命令:
ipcs -q:显示消息队列基本信息
ipcs -q -l:显示消息队列限制信息
ipcs -q -i msgid:查看指定消息队列的详细信息
ipcs -q -i 12124195 命令显示:
Message Queue msqid=0
uid=1000 gid=1000 cuid=1000 cgid=1000 mode=0666
cbytes=0 qbytes=16384 qnum=0 lspid=12239 lrpid=12238
send_time=Sat Nov 29 22:13:44 2025
rcv_time=Sat Nov 29 22:13:44 2025
change_time=Sat Nov 29 22:12:20 2025
*/
#define TYPE_A 100
#define TYPE_B 200
#define LEN 64
#define MSGPATH "."
typedef struct
{
long mtype;
char mtext[LEN];
} MSG;
#define TXT_LEN (sizeof(MSG) - sizeof(long))
int getMsgId()
{
int msgid;
key_t key;
if ((key = ftok(MSGPATH, 'm')) < 0)
{
perror("fail to ftok");
exit(-1);
}
if ((msgid = msgget(key, IPC_CREAT|0666)) < 0)//创建或打开消息队列
{
perror("fail to msgget");
exit(-1);
}
printf("msgid=%d\n",msgid);
return msgid;
}
int testWrite()
{
int msgid = getMsgId();
while (true)
{
printf("input send TYPE_A msg : ");
MSG buf;
memset(&buf,0,sizeof(MSG));
fgets(buf.mtext, LEN, stdin);
buf.mtype = TYPE_A;
msgsnd(msgid, &buf, TXT_LEN, 0);//添加TYPE_A消息
if (strncmp(buf.mtext, "quit", 4) == 0)
{
msgctl(msgid, IPC_RMID, NULL);//从系统中删除消息队列
break;
}
printf("input send TYPE_B msg : ");
memset(&buf,0,sizeof(MSG));
fgets(buf.mtext, LEN, stdin);
buf.mtype = TYPE_B;
msgsnd(msgid, &buf, TXT_LEN, 0);//添加TYPE_B消息
if (strncmp(buf.mtext, "quit", 4) == 0)
{
msgctl(msgid, IPC_RMID, NULL);//从系统中删除消息队列
break;
}
}
return 0;
}
int testRead()
{
int msgid = getMsgId();
while (true)
{
MSG buf;
memset(&buf,0,sizeof(MSG));
if(-1 == msgrcv(msgid, &buf, TXT_LEN, TYPE_A, 0))//读取消息
{
printf("recv message error\n");
break;
}
if (strncmp(buf.mtext, "quit", 4) == 0)
{
break;
}
printf("recv TYPE_A from message queue : %s", buf.mtext);
memset(&buf,0,sizeof(MSG));
if(-1 == msgrcv(msgid, &buf, TXT_LEN, TYPE_B, 0))//读取消息
{
printf("recv message error\n");
break;
}
if (strncmp(buf.mtext, "quit", 4) == 0)
{
break;
}
printf("recv TYPE_B from message queue : %s", buf.mtext);
}
return 0;
}
int main(int argc ,char**argv)
{
if(argc > 1)
testWrite();
else
testRead();
return 0;
}