《Linux系统编程篇》消息队列(Linux 进程间通信(IPC))——基础篇

文章目录

"山重水复疑无路,柳暗花明又一村。" ------陆游

引言

《Linux系统编程篇》------基础篇首页传送门

想象一下,你正在开发一个多任务处理的应用程序,其中需要不同的模块之间进行数据交换和协作。这时,消息队列就像是一个快递站,负责接收、存储和转发各个模块之间的信息。发送者将消息放入队列,接收者则可以从队列中取出消息并进行处理,实现了模块之间的解耦和异步通信。

消息队列(Message Queue)

消息队列是一种更高级的 IPC 方式,允许多个进程之间以消息的形式进行数据交换。消息队列提供了有序的数据传输,并且允许对消息进行优先级排序。

消息队列是存放消息的链表,他存在于Linux内核当中,每一个消息队列用一个标识符也就是队列id来标识。

消息队列的特点

1、消息队列可以独立发送与接受,成功创建后,如果进程结束,消息队列节点并不会消失,他的消失是由Linux内核 来管理的
2、消息队列是面向记录的,有特定格式及特点的优先级
3、消息队列可以实现消息的随机查询,消息不一定要以先进先出的顺序依次读取,也可以使用消息类型读取。

消息队列的特性

  • 异步通信:发送方和接收方不需要同时在线,可以分别发送和接收消息。

  • 消息缓存:消息队列可以缓存一定数量的消息,接收方可以按需处理。

  • 消息优先级:消息队列通常支持消息的优先级设定,确保重要消息被优先处理。

  • 消息持久性:消息队列通常支持消息的持久化,即使接收方不在线,消息也不会丢失。

函数原型及结构体

c 复制代码
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系统调用删除不再需要的消息队列。

用法

  1. 使用 msgget() 创建或获取消息队列。
  2. 使用 msgsnd() 发送消息,msgrcv() 接收消息。
  3. 消息队列通过键值(key)来标识,且在内核中驻留。

示例代码:

本次的示例代码为单进程,可以分为两个文件,实现多进程的消息队列通讯,学员们可以自己动手敲一下感受一下。

c 复制代码
#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)对象,包括消息队列、信号量和共享内存。

信号量和共享内存我们以后会介绍到。

bash 复制代码
ipcs -q

这将列出系统中所有的消息队列,包括它们的标识符(ID)、拥有者、权限、大小等信息。您可以通过这些信息了解系统中消息队列的使用情况。

如果在上述代码中不删除则会

ipcrm 拓展

在Linux系统中,您可以使用ipcrm命令手动删除消息队列。ipcrm命令用于删除System V IPC 对象(包括消息队列、信号量和共享内存)。

要手动删除消息队列,您需要知道消息队列的标识符(ID)。首先,您可以使用ipcs -q命令列出系统中的消息队列及其ID,然后选择要删除的消息队列的ID。

bash 复制代码
ipcrm -q <queue_id>

其中,<queue_id> 是要删除的消息队列的标识符(ID)。

例如,如果要删除标识符为12345的消息队列,您可以运行以下命令:

bash 复制代码
ipcrm -q 12345

比如我要手动删除我刚刚没有删除的的消息队列。

注意事项

  1. 消息格式一致性:发送和接收进程之间必须约定好消息的格式,包括消息的大小、结构和编码方式。确保发送的消息可以被接收进程正确解析和处理。

  2. 消息队列容量:消息队列有容量限制,当消息队列满时,发送进程可能被阻塞或消息被丢弃。需要根据实际需求设置合适的消息队列容量,避免消息丢失或系统阻塞。

  3. 进程同步:在使用消息队列进行通信时,需要考虑进程之间的同步和互斥,避免出现竞争条件和数据不一致的情况。可以使用信号量等机制来实现进程间的同步。


结论

消息队列通常用于进程间通信,特别是在需要解耦发送者和接收者、实现异步通信的情况下。

通过学习消息队列,希望学员们将能够更好地理解并应用进程间通信的技术,为构建复杂的软件系统打下坚实的基础。

相关推荐
IC 见路不走1 小时前
LeetCode 第91题:解码方法
linux·运维·服务器
翻滚吧键盘2 小时前
查看linux中steam游戏的兼容性
linux·运维·游戏
小能喵2 小时前
Kali Linux Wifi 伪造热点
linux·安全·kali·kali linux
汀沿河2 小时前
8.1 prefix Tunning与Prompt Tunning模型微调方法
linux·运维·服务器·人工智能
zly35002 小时前
centos7 ping127.0.0.1不通
linux·运维·服务器
小哥山水之间3 小时前
基于dropbear实现嵌入式系统ssh服务端与客户端完整交互
linux
ldj20203 小时前
2025 Centos 安装PostgreSQL
linux·postgresql·centos
翻滚吧键盘3 小时前
opensuse tumbleweed上安装显卡驱动
linux
黑听人3 小时前
【力扣 简单 C】70. 爬楼梯
c语言·leetcode
杜子不疼.4 小时前
二分查找,乘法口诀表,判断闰年,判断素数,使用函数实现数组操作
c语言