“山重水复疑无路,柳暗花明又一村。” ——陆游
引言
《Linux系统编程篇》——基础篇首页传送门
想象一下,你正在开发一个多任务处理的应用程序,其中需要不同的模块之间进行数据交换和协作。这时,消息队列就像是一个快递站,负责接收、存储和转发各个模块之间的信息。发送者将消息放入队列,接收者则可以从队列中取出消息并进行处理,实现了模块之间的解耦和异步通信。
消息队列(Message Queue)
消息队列是一种更高级的 IPC 方式,允许多个进程之间以消息的形式进行数据交换。消息队列提供了有序的数据传输,并且允许对消息进行优先级排序。
消息队列是存放消息的链表,他存在于Linux内核当中,每一个消息队列用一个标识符也就是队列id来标识。
消息队列的特点
1、消息队列可以独立发送与接受,成功创建后,如果进程结束,消息队列节点并不会消失,他的消失是由Linux内核 来管理的
2、消息队列是面向记录的,有特定格式及特点的优先级
3、消息队列可以实现消息的随机查询,消息不一定要以先进先出的顺序依次读取,也可以使用消息类型读取。
消息队列的特性
-
异步通信:发送方和接收方不需要同时在线,可以分别发送和接收消息。
-
消息缓存:消息队列可以缓存一定数量的消息,接收方可以按需处理。
-
消息优先级:消息队列通常支持消息的优先级设定,确保重要消息被优先处理。
-
消息持久性:消息队列通常支持消息的持久化,即使接收方不在线,消息也不会丢失。
函数原型及结构体
typedef struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
}msg;
//获取消息队列id号
int msgget(key_t key, int msgflg);
//发送消息
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
//接受消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
//控制队列(用来销毁)
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
一图带你了解消息队列
消息队列的操作
-
创建消息队列:使用
msgget
系统调用创建消息队列,返回一个标识符(消息队列ID)。 -
发送消息:使用
msgsnd
系统调用向消息队列发送消息。 -
接收消息:使用
msgrcv
系统调用从消息队列接收消息。 -
删除消息队列:使用
msgctl
系统调用删除不再需要的消息队列。
用法
- 使用
msgget()
创建或获取消息队列。 - 使用
msgsnd()
发送消息,msgrcv()
接收消息。 - 消息队列通过键值(key)来标识,且在内核中驻留。
示例代码:
本次的示例代码为单进程,可以分为两个文件,实现多进程的消息队列通讯,学员们可以自己动手敲一下感受一下。
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
struct msg_buffer {
long msg_type;
char msg_text[100];
} message;
int main() {
key_t key = ftok("progfile", 65); // 生成消息队列键
int msgid = msgget(key, 0666 | IPC_CREAT); // 创建消息队列
// 向消息队列发送消息
message.msg_type = 1;
strcpy(message.msg_text, "Hello from sender!");
msgsnd(msgid, &message, sizeof(message), 0);
printf("Sent message: %s\n", message.msg_text);
// 接收消息
msgrcv(msgid, &message, sizeof(message), 1, 0);
printf("Received message: %s\n", message.msg_text);
msgctl(msgid, IPC_RMID, NULL); // 删除消息队列
return 0;
}
运行结果
ipcs -q 拓展
在Linux系统中,可以使用ipcs
命令来查看系统中的消息队列信息。ipcs
命令可以列出系统中当前存在的进程间通信(IPC)对象,包括消息队列、信号量和共享内存。
信号量和共享内存我们以后会介绍到。
ipcs -q
这将列出系统中所有的消息队列,包括它们的标识符(ID)、拥有者、权限、大小等信息。您可以通过这些信息了解系统中消息队列的使用情况。
如果在上述代码中不删除则会
ipcrm 拓展
在Linux系统中,您可以使用ipcrm
命令手动删除消息队列。ipcrm
命令用于删除System V IPC 对象(包括消息队列、信号量和共享内存)。
要手动删除消息队列,您需要知道消息队列的标识符(ID)。首先,您可以使用ipcs -q
命令列出系统中的消息队列及其ID,然后选择要删除的消息队列的ID。
ipcrm -q <queue_id>
其中,<queue_id>
是要删除的消息队列的标识符(ID)。
例如,如果要删除标识符为12345的消息队列,您可以运行以下命令:
ipcrm -q 12345
比如我要手动删除我刚刚没有删除的的消息队列。
注意事项
-
消息格式一致性:发送和接收进程之间必须约定好消息的格式,包括消息的大小、结构和编码方式。确保发送的消息可以被接收进程正确解析和处理。
-
消息队列容量:消息队列有容量限制,当消息队列满时,发送进程可能被阻塞或消息被丢弃。需要根据实际需求设置合适的消息队列容量,避免消息丢失或系统阻塞。
-
进程同步:在使用消息队列进行通信时,需要考虑进程之间的同步和互斥,避免出现竞争条件和数据不一致的情况。可以使用信号量等机制来实现进程间的同步。
结论
消息队列通常用于进程间通信,特别是在需要解耦发送者和接收者、实现异步通信的情况下。
通过学习消息队列,希望学员们将能够更好地理解并应用进程间通信的技术,为构建复杂的软件系统打下坚实的基础。