目录
前言
01 消息队列
02 如何创建队列
小结
前言
🎬 个人主页:@ChenPi
🐻推荐专栏1: 《Linux C应用编程(概念类)_@ChenPi的博客-CSDN博客》✨✨✨
🔥 推荐专栏2: 《C++_@ChenPi的博客-CSDN博客》✨✨✨
🛸推荐专栏3: 《链表_@ChenPi的博客-CSDN博客 》 ✨✨✨
🌺本篇简介 : 这一章我们学习Linux进程间通信中的消息队列
在 Linux系统中,以进程为单位分配和管理资源。
由于保护的缘故,一个进程不能直接访问另一个进程的资源,也就是说,进程之间互相封闭。
但在一个复杂的应用系统中,通常会使用多个相关的进程来共同完成一项任务,因此要求进程之间必须能够互相通信,从而来共享资源和信息。
所以,一个操作系统内核必须提供进程间的通信机制(IPC)。
目前,Linux使用的进程间的通信方式主要有
管道(pipe)和有名管道(FIFO)
信号(signal)
消息队列
共享内存
信号量
套接字(socket)
本节中,将消息队列和使用 进行讲解
01 消息队列
消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
我的理解是这样的,如果有什么不对,欢迎大佬指正
特点
- 消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
- 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
- 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
函数原型
#include <sys/msg.h>// 创建或打开消息队列:成功返回队列ID,失败返回-1
int msgget(key_t key, int flag);// 队列中添加消息:成功返回0,失败返回-1
int msgsnd(int msqid, const void *ptr, size_t size, int flag);// 在队列中读取消息:成功返回消息数据的长度,失败返回-1
int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);// 控制消息队列:成功返回0,失败返回-1
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
02 如何创建队列
在以下两种情况下,msgget将创建一个新的消息队列:
- 如果没有与键值key相对应的消息队列,并且flag中包含了IPC_CREAT标志位。
- key参数为IPC_PRIVATE。
int msgfd = msgget(1111,IPC_CREAT|0600);if(-1 == msgfd) {puts("msgget failed");}
这个key的参数我看源码是一个整形数,我就想试一下给他一个整形数行不行
函数msgrcv在读取消息队列时,type参数有下面几种情况:
- type == 0,返回队列中的第一个消息;
- type > 0,返回队列中消息类型为 type 的第一个消息;
- type < 0,返回队列中消息类型值小于或等于 type 绝对值的消息,如果有多个,则取类型值最小的消息。
可以看出,type值非 0 时用于以非先进先出次序读消息。也可以把 type 看做优先级的权值。
例子
下面写了一个简单的使用消息队列进行IPC的例子,服务端程序一直在等待特定类型的消息,当收到该类型的消息以后,发送另一种特定类型的消息作为反馈,客户端读取该反馈并打印出来。
msg_get.c 获取来自send.c发来的数据
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>struct Msgbuf
{long mtype;char buf[128];
};int main()
{struct Msgbuf msg;int msgfd = msgget(1111,IPC_CREAT|0600);if(-1 == msgfd) {puts("msgget failed");}msgrcv(msgfd, &msg, sizeof(msg.buf),888, 0);printf("read msg from client %s\n",msg.buf);return 0;
}
msg_send.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>struct Msgbuf
{long mtype;char buf[128];
};int main()
{struct Msgbuf msg = {888,"I am client"};int msgfd = msgget(1111,IPC_CREAT|0600);if(-1 == msgfd) {puts("msgget failed");}msgsnd(msgfd, &msg, strlen(msg.buf),0);printf("read msg from client %s\n",msg.buf);return 0;
}
这里需要注意的就是,除了要注意创建或打开消息队列的key值要一致时,还有就是,发送接收消息的类型也要对应才能找到对应数据,就是示例代码中的888
小结
- 采用消息队列通信比采用管道通信具有更多的灵活性,通信的进程不但没有血缘上的要求,也不需要进行同步处理。
- 消息队列是一种先进先出的队列型数据结构;
- 消息队列将输出的信息进行了打包处理,可以保证以消息为单位进行接收;
- 消息队列对信息进行分类服务,根据消息的类别进行分别处理。
- 提供消息数据自动拆分功能,同时不能接受两次发送的消息。
- 消息队列提供了不完全随机读取的服务。
- 消息队列提供了完全异步的读写服务。