目录
一、前言
二、认识消息队列
1、什么是队列?
2、队列动图演示
3、消息队列
三、消息队列相关函数
1、msgget()函数
2、msgsnd()函数
3、msgrcv()函数
四、实战演练(使用消息队列实现两个进程互相聊天)
1、发送消息端
2、接收消息端
3、实现效果
五、总结
一、前言
回顾一下关于进程间的通信(IPC,InterProcess Communication)我们学习了哪些二、认识消息队列
今天来学习一个新的IPC通信: 消息队列
- 1??信号 :信号的使用
- 2??管道:管道的使用
- 3??共享内存:共享内存的使用
- 学习消息队列之前我们先简单了解一下队列(Queue)
队列是一种 特殊的线性表 ,特殊之处在于它只允许在表的前端进行删除操作,而在表的后端进行插入操作。进行 插入操作的端称为队尾 ,进行 删除操作的端称为队头 。2、队列动图演示
- 下面是博主用ppt做的动图,可以形象生动的演示队列 入队出队 的操作
记笔记
??:队列是一种特殊的 线性表3、消息队列
??:数据只能从队列的 队尾入队,队头出队
??:队列的特点是 先进先出
- 消息队列其实就是一个严格意义上的队列,在消息入队出队过程中,保证这些消息严格有序
:消息队列提供了一个 从一个进程向另外一个进程发送一块数据 的方法。
:因为队列先进先出的特点,所以先发送的消息先收到, 保证 消息严格有序 。
:消息队列也有管道一样的不足,就是 每个数据块的最大长度是有上限的 ,系统上全体队列的 最大总长度也有一个上限 。
:一个进程发送的 消息会保留在消息队列中 ,直到另一个进程读取了队列中的消息,消息才会从消息队列 “出队” 。
三、消息队列相关函数
- 下面为创建消息队列和使用消息队列用到的几个函数
- 用来创建和访问一个消息队列,消息队列不存在则创建,存在则访问
头文件
#include
#include
#include
函数原型
int msgget(key_t key, int msgflg);
参数
key??某个消息队列的名字。
msgflg??由九个权限标志构成,用法和创建文件时使用的mode模式标志是一样的。
返回值
成功:将返回一个 非负整数 ,即该消息队列的 标识码
失败:返回 “-1”
- 下面为创建消息队列的代码
#include
#include
#include
#include
#include using namespace std;
int main()
{
int msgid = 0;
//消息队列不存在则创建存在则访问
msgid = msgget((key_t)1001, IPC_CREAT | 0777);
if (msgid == -1)
{
perror("msgget error");
}
else
{
cout << "消息队列创建成功 " << "msgid = " << msgid << endl;
}
return 0;
}
- 在linux下找到对应的main.cpp ,通过g++ 的方式编译, ./ 运行
文章图片
可以看见消息队列创建成功,且 id 为131072
- 通过命令: ipcs ,可以看见我们新创建出来的消息队列,权限为777, id 为131072 。
文章图片
- 可以通过命令 ipcrm -a 将创建出来的消息队列删掉
文章图片
2、msgsnd()函数
- 用于把一条消息添加到消息队列里去
头文件
#include
#include
#include
函数原型
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数
msqid??由msgget() 函数返回的消息队列标识码。
msgp??是一个指针,指针指向准备发送的消息。
msgsz??指向的消息长度,这个长度不能保存消息类型的那个“long int”长整型计算在内。
msgflg??控制着当前消息队列满或到达系统上限时将要发生的事情,为0即可。
返回值
成功:返回 1
失败:返回 -1
- 发送的消息结构应该用如下结构体
消息结构体
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[50]; /* message data */
};
注意
发送信息前应该 先用这个 mtype 确定消息的类型 ,接收消息时会用到这个 mtype。
3、msgrcv()函数
- 作用是从一个消息队列里检索消息,即读取消息。读取一条消息,该消息就 “出队”。
头文件记笔记
#include
#include
#include
函数原型
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数
msqid??由msgget() 函数返回的消息队列标识码。
msgp??是一个指针,指针指向准备接收的消息。
msgsz??指向的消息长度,这个长度不能保存消息类型的那个“long int”长整型计算在内。
msgtyp??发送消息时指定的 msgtyp。
msgflg??控制着队列中没有相应类型的消息可供接收时将要发生的事,为0即可。
返回值
成功:返回 实际放到接收缓冲区里去的字符个数
失败:返回 -1
??:msgrcv()函数是一个 阻塞函数 ,只有读到消息才会继续执行。
好了,消息队列使用到的函数就介绍到这里了,接下来通过一个代码实战来巩固消化这些知识,话不多说
文章图片
四、实战演练(使用消息队列实现两个进程互相聊天) 1、发送消息端
发送消息端,通过控制台输入,先 发 消息类型(msgtyp)为 1 的消息,再等待 接收 对方发过来的消息类型(msgtyp)为 2 的消息。
#include
#include
#include
#include
#include
#include using namespace std;
typedef struct sndMsgbuf
{
long mtype;
/* message type, must be > 0 */
char mtext[50];
/* message data */
}MSGBUF;
int main()
{
int msgid = 0;
MSGBUF sendbuf;
//消息队列不存在则创建存在则访问
msgid = msgget((key_t)1001, IPC_CREAT | 0777);
if (msgid == -1)
{
perror("msgget error");
}
else
{
cout << "消息队列创建成功 " << "msgid = " << msgid << endl;
}
while (1)
{
//先发送消息
//指定发送消息类型为 1
sendbuf.mtype = 1;
cin >> sendbuf.mtext;
//控制台输入作为消息数据
int res = msgsnd(msgid, &sendbuf, sizeof(sendbuf.mtext), 0);
if (res == -1)
{
perror("msgsnd error");
}
else
{
cout << "消息已发送" << endl;
cout << endl;
bzero(&sendbuf, sizeof(sendbuf));
//再接收消息
//msgrcv为阻塞函数 接收消息类型为 2 的消息
int res = msgrcv(msgid, &sendbuf, sizeof(sendbuf.mtext), 2, 0);
if (res == -1)
{
perror("msgrcv error");
}
else
{
cout << "对方发来一条消息: " << sendbuf.mtext << endl;
cout << endl;
bzero(&sendbuf, sizeof(sendbuf));
}
}
}
return 0;
}
2、接收消息端
接收消息端,先等待 接收 对方发过来的消息类型(msgtyp)为 1 的消息,再通过控制台输入, 发送 消息类型(msgtyp)为 2 的消息。
#include
#include
#include
#include
#include
#include using namespace std;
typedef struct rcvMsgbuf
{
long mtype;
/* message type, must be > 0 */
char mtext[50];
/* message data */
}MSGBUF;
int main()
{
int msgid = 0;
MSGBUF receivebuf;
msgid = msgget((key_t)1001, IPC_CREAT | 0777);
if (msgid == -1)
{
perror("msgget error");
}
else
{
cout << "消息队列创建成功 " << "msgid = " << msgid << endl;
}
while (1)
{
//先接收消息
//msgrcv为阻塞函数 接收消息类型为 1 的消息
int res = msgrcv(msgid, &receivebuf, sizeof(receivebuf.mtext), 1, 0);
if (res == -1)
{
perror("msgrcv error");
}
else
{
cout << "对方发来一条消息: " << receivebuf.mtext << endl;
cout << endl;
bzero(&receivebuf, sizeof(receivebuf));
//再发送消息
//指定发送消息类型为 2
receivebuf.mtype = 2;
cin >> receivebuf.mtext;
//控制台输入作为消息数据
int res = msgsnd(msgid, &receivebuf, sizeof(receivebuf.mtext), 0);
if (res == -1)
{
perror("msgsnd error");
}
else
{
cout << "消息已发送" << endl;
cout << endl;
bzero(&receivebuf, sizeof(receivebuf));
}
}
}
return 0;
}
3、实现效果
- 在linux下通过g++的方式进行编译,在用 ./ 的方式运行,测试结果如下
写端先发消息,然后读端收到消息后再发送给写端,循环往复完成回合制聊天。
文章图片
五、总结
??:由于队列先进先出的特点,可以保证 消息按序接收 。
??:发送消息端和接收消息端发送的 消息类型(msgtyp)要不一致 ,否则消息收发会乱套。
??:消息发送出去就存在消息队列里,只有当某个进程读取里面的内容时, 读几条消息就“出队”几条 。
??:每个数据(消息)块的最大长度是有上限的,系统上全体队列的最大总长度也有一个上限,即 无法进行大数据传输 。
??:msgrcv()函数是一个 阻塞函数 ,只有读到消息才会继续执行。
原创不易,转载请标明出处。
【linux远程开发|linux远程开发——(IPC通信)消息队列的使用】对您有帮助的话可以一键三连,会持续更新的(嘻嘻)。
推荐阅读
- linux远程开发|linux远程开发——(IPC通信)共享内存的使用
- linux远程开发|linux远程开发——信号的使用(信号绑定和发送)
- linux远程开发|linux远程开发——使用vs2019远程连接linux
- linux远程开发|linux远程开发——网络通信(客户端与服务器建立连接)
- python|python 车牌识别简单_Python利用百度云接口实现车牌识别
- 面试实习|关于RabbitMQ的一些面试题
- linux|linux vs 安装程序,在Linux中安装VSCodium(100%开源的Microsoft VS Code)
- 延迟队列
- VS|ESP32 TTGO 1.14寸液晶屏使用 TFT_eSPI库驱动