1906 字
10 分钟

消息队列

2025-11-11
浏览量 加载中...

消息队列

介绍消息队列前,先说明system V所提供的ipc对象

与内核提供的管道、信号通信不同:system V的ipc对象实现了数据传递的容器与程序相分离,也就是说,即使程序以己经结束,但是放入到容器中的数据依然存在,除非将容器手动删除

消息队列是system V提供的一种用于多进程间进行通信的IPC对象,与linux内核提供的管道文件和信号不同,他支持双向通信,而管道文件只支持单向通信,信号则用于进程间的通知,例如子进程推出后,会向父进程发送SIGCHLD信号。相似的IPC对象还有共享内存,信号量

消息队列要保证不同的进程间打开的是相同的消息队列,需要有一个key值类似于宝箱的钥匙,不同的进程可以通过同一个key值打开同一个消息队列,对消息队列进行读取或写入

上图是消息队列的实现原理

消息队列的API

1、创建key值 #include <sys/types.h> #include <sys/ipc.h> key_t ftok(const char *pathname, int proj_id); //ftok(”/”, ‘k’);

功能:通过给定的文件以及给定的一个随机值,创建出一个4字节整数的key值,用于system V IPC对象的创建 参数1:一个文件路径,要求是已经存在的文件路径,提供了key值3字节的内容,其中,文件的设备号占1字节,文件的inode号占2字节 参数2:一个随机整数,取后8位(1字节)跟前面的文件共同组成key值,必须是非0的数字 返回值:成功返回key值,失败返回-1并置位错误码

2、通过key值,创建消息队列

#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgget(key_t key, int msgflg);

功能:通过给定的key值,创建出一个消息队列的对象,并返回消息队列的句柄ID,后期可以通过该ID操作整个消息队列 参数1:key值,该值可以是IPC_PRIVATE,也可以是ftok创建出来的,前者只用于亲缘进程间的通信 参数2:创建标识 IPC_CREAT:创建并打开一个消息队列,如果消息队列已经存在,则直接打开 IPC_EXCL:确保本次创建处理的是一个新的消息队列,如果消息队列已经存在,则报错,错 误码位EEXIST 0664:该消息队列的操作权限 eg: IPC_CREAT|0664 或者 IPC_CREAT|IPC_EXCL|0664 返回值:成功返回消息队列的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);

功能:向消息队列中存放一个指定格式的消息 参数1:打开的消息队列的id号 参数2:要发送的消息的起始地址,消息一般定义为一个结构体类型,由用户手动定义

struct msgbuf

{ long mtype; /* message type, must be > 0 / 消息的类型 char mtext[1]; / message data */ 消息正文 };

参数3:消息正文的大小 参数4:是否阻塞的标识 0:标识阻塞形式向消息队列中存放消息,如果消息队列满了,就在该函数处阻塞 IPC_NOWAIT:标识非阻塞的形式向消息队列中存放消息,如果消息队列满了,直接返回 返回值:成功返回0,失败返回-1并置位错误码

4、从消息队列中取消息

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);

功能:从消息队列中取数指定类型的消息放入给定的容器中 参数1:打开的消息队列的id号 参数2:要接收的消息的起始地址,消息一般定义为一个结构体类型,由用户手动定义

struct msgbuf { long mtype; /* message type, must be > 0 / 消息的类型 char mtext[1]; / message data */ 消息正文 };

参数3:消息正文的大小 参数4:要接收的消息类型 0:表示每次都取消息队列中的第一个消息,无论类型

0:读取队列中第一个类型为msgtyp的消息 <0:读取队列中的一个消息,消息为绝对值小于msgtyp的第一个消息 eg: 10—>8—>3—>6—>5—>20—>2 -5: 会从队列中绝对值小于5的类型的消息中选取第一个消息,就是3 参数5:是否阻塞的标识 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);

功能:对给定的消息队列执行相关的操作,该操作由cmd参数而定 参数1:消息队列的ID号 参数2:要执行的操作 IPC_RMID:删除一个消息队列,当cmd为该值时,第三个参数可以省略填NULL即可 IPC_STAT:表示获取当前消息队列的属性,此时第三个参数就是存放获取的消息队列属性的容器起始地址 IPC_SET:设置当前消息队列的属性,此时第三个参数就是要设置消息队列的属性数据的起始地址 参数3:消息队列数据容器结构体,如果第二个参数为IPC_RMID,则该参数忽略填NULL即可,如果 是 IPC_STAT、 IPC_SET填如下结构体:

struct msqid_ds { struct ipc_perm msg_perm; /* Ownership and permissions / 消息队列的拥有者和权限 time_t msg_stime; / Time of last msgsnd(2) / 最后一次发送消息的时间 time_t msg_rtime; / Time of last msgrcv(2) / 最后一次接收消息的时间 time_t msg_ctime; / Time of last change / 最后一次状态改变的时间 unsigned long __msg_cbytes; / Current number of bytes in queue(nonstandard) / 已用字节数 msgqnum_t msg_qnum; / Current number of messages in queue / 消息队列中消息个数 msglen_t msg_qbytes; / Maximum number of bytes allowed in queue /最大消息个数 pid_t msg_lspid; / PID of last msgsnd(2) / 最后一次发送消息的进程pid pid_t msg_lrpid; / PID of last msgrcv(2) / 最后一次读取消息的进程pid }; 该结构体的第一个成员类型如下 struct ipc_perm { key_t __key; / Key supplied to msgget(2) / key值 uid_t uid; / Effective UID of owner / 当前进程的uid gid_t gid; / Effective GID of owner / 当前进程的组ID uid_t cuid; / Effective UID of creator / 消息队列创建者的用户id gid_t cgid; / Effective GID of creator / 消息队列创建者的组id unsigned short mode; / Permissions / 消息队列的权限 unsigned short __seq; / Sequence number */ 队列号 }; 返回值:成功返回0,失败返回-1并置位错误码

注意事项:

1、对于消息而言,由两部分组成:消息的类型和消息正文,消息结构体由用户自定义 2、对于消息队列而言,任意一个进程都可以向消息队列中发送消息,也可以从消息队列中取消息 3、多个进程,使用相同的key值打开的是同一个消息队列 4、对消息队列中的消息读取操作是一次性的,被读取后,消息队列中不存在该消息了 5、消息队列的大小:16K

赞助支持

如果这篇文章对你有帮助,欢迎赞助支持!

赞助
消息队列
https://firefly.cuteleaf.cn/posts/消息队列/
作者
Shadow
发布于
2025-11-11
许可协议
CC BY-NC-SA 4.0
最后更新于 2025-11-11,距今已过 2 天

部分内容可能已过时

评论区

目录