Linux系统编程系列之进程间通信-消息队列

news2024/11/27 3:42:29

一、什么是消息队列

        消息队列是system-V三种IPC对象之一,是进程间通信的一种方式。

二、消息队列的特性

        允许发送的数据携带类型(指定发送给谁),具有相同类型的数据在消息队列内部排队,读取的时候也要指定类型,然后依次读出数据。可以理解为消息队列就是一个多管道集合

三、消息使用场景

        由于每个消息都携带有类型,相同的类型自成一队,因此读取方向可以根据类型来挑选不同的队列,所以说MSG适用于“多对一”的场景。

        (1)系统日志。

        (2)多个不同的,不相关的进程向同一管道输入数据。

四、函数API接口

        1、指定消息队列功能

// 指定消息队列功能
int msgget(key_t key, int msgflg);

// 接口说明:
    返回值:消息队列MSG对象ID
    参数key:键值,全局唯一标识,可由ftok()产生
    参数msgflg:操作模式与读写权限,与文件操作函数open类似。

         2、向MSG对象发送消息

// 向MSG对象发送消息
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

// 接口说明
    msggid:MSG对象的ID,由msgget()获取
    msgp:一个指向等待被发送的消息的指针,由于MSG中的消息最大的特点是必须有一个整数标识,用以区分MSG中的不同的消息,因此MSG的消息会使用一个特别的结构体来表达:

struct msgbuf
{
    long mtype;    // 消息类型固定,必须大于0
    char text[100];    // 消息正文(可变,自己定义)
    
};

    msgsz:消息正文的长度(单位字节),注意不含类型长度
    msgflg:发送选项
    0:默认发送模式,在MSG缓冲区已满的情形下阻塞,直到缓冲区变为可用状态
    IPC_NOWAIT:非阻塞发送模式,在MSF缓冲区已满的情形下直接退出函数并设置错误码为EAGAIN

        3、从MSG对象接收消息

// 从MSG对象接收消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

// 接口说明
    msgqid:MSG对象ID,由msgget()获取
    msgp:存放消息的内存入口
    msgsz:存放消息的内存大小
    msgtyp:欲接收消息的类型
        0:不区分类型,自己读取MSG中的第一个消息
        大于0:读取类型为指定msgtyp的第一个消息(若msgfla被配置了MSG_EXCEPT则读取除了类型msgtyp的第一个消息)
        小于0:读取类型小于等于msgtyp绝对值的第一个具有最小类型的消息。
    msgflg:接收选项
        0:默认接收模式,在MSG中无指定类型消息时阻塞
        IPC_NOWAIT:非阻塞接收模式,在MSG中无指定类型消息时直接退出函数并设置错误码为ENOMSG
        MSG_EXCEPT:读取出msgtyp之外的第一个消息
        MSG_NOERROR:如果待读取的消息尺寸比msgsz大,直接切割消息并返回msgsz部分,读不了的部分直接丢弃。若没有设置该项,则函数将出错返回并设置错误码为E2BIG

        4、删除消息队列对象

        在前一篇博客IPC对象中有讲,可以使用命令来删除,同时也可以采用函数的方式来删除

// 删除MSG对象
int msgctl(int msqid, int cmd, struct msgqid_ds *buf);

// 接口说明
msqid:MSG对象ID
cmd:控制命令字
    IPC_STAT:获取该MSG的信息,储存在结构体msgqid_ds中
    IPC_SET: 设置该MSG的信息,储存在结构体msgqid_ds中
    IPC_RMID:立即删除该MSG,并且唤醒所有阻塞在该MSG上的进程,同时忽略第三个参数

五、消息队列使用步骤

        1、使用ftok()获取key值

        2、调用msgget(),指定为消息队列

        3、调用msgsnd()或者msgrcv()来发送或者接收信息。

        4、使用命令或者函数删除消息队列(可选)。

六、案例

        使用消息队列来实现两个进程间进行相互收发信息

// 消息队列的案例

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

// 编译版本,一个直接编译,另外一个把0x01和0x02位置互换后编译
#define SEND_MTYPE 0x01
#define RECV_MTYPE 0x02

struct msgbuf 
{
    long mtype;      // 消息类型,固定的,必须大于0 
    char mtext[32];  // 可变的,自己定义
};


int main(int argc, char *argv[])
{
    // 1、获得KEY值
    key_t msg_key = ftok("./", 1);
    if(msg_key == -1)
    {
        perror("ftok fail");
        return -1;
    }

    // 2、指定消息队列功能
    int msg_id = msgget(msg_key, IPC_CREAT | 0666);
    if(msg_id == -1)
    {
        perror("msgget fail");
        return -1;
    }

    // 3、消息队列的读写操作
    struct msgbuf Buf = {0};
    int ret = 0;
    pid_t pid = fork();
    // 父进程
    if(pid > 0)
    {   
        Buf.mtype = SEND_MTYPE; // 指定消息类型
        while(1)
        {
            printf("please input data:\n");
            // fgets("%s", Buf.mtext);
            fgets(Buf.mtext, sizeof(Buf.mtext), stdin);
            // 发送消息
            ret = msgsnd(msg_id, &Buf, sizeof(Buf.mtext), 0);
            if(ret == -1)
            {
                perror("msgsnd fail");
            }
            else if(ret == 0)
            {
                printf("send data success: %s\n", Buf.mtext);
            }
            memset(Buf.mtext, 0, sizeof(Buf.mtext));
        }
    }
    // 子进程
    else if(pid == 0)
    {
        Buf.mtype = RECV_MTYPE; // 指定消息类型
        while(1)
        {
            // 接收消息
            ret = msgrcv(msg_id, &Buf, sizeof(Buf.mtext), Buf.mtype, 0);
            if(ret > 0)
            {
                printf("read data success: %s\n", Buf.mtext);
            }
        }
    }
    else
    {
        perror("fork fail");
        return -1;
    }

    return 0;
}

        注:编译时,编译两个版本,一个直接编译,另外一个把两个宏定义的数值互换位置再编译

七、总结

        消息队列可以理解为一个多管道的集合,通常用于多对一的场景,操作消息队列需要遵循一定的步骤,可以结合案例来加深对消息队列的理解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1053021.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32三种开发方式及标准库和HAL库的编程差异

三种开发方式 STM32基于标准库函数和HAL库编程差异_stm32库函数和hal库-CSDN博客本文目的是以串口通信来简要分析STM32使用标准库函数和HAL库函数编程的差异。目录&#xff08;一&#xff09;开发方式1.配置寄存器2.库函数3.HAL库&#xff08;二&#xff09;库函数与HAL库对比…

格点数据可视化(美国站点的日降雨数据)

获取美国站点的日降雨量的格点数据&#xff0c;并且可视化 导入模块 from datetime import datetime, timedelta from urllib.request import urlopenimport cartopy.crs as ccrs import cartopy.feature as cfeature import matplotlib.colors as mcolors import matplotli…

3D孪生场景搭建:模型区域摆放

前面介绍完了NSDT场景编辑器的线性绘制和阵列绘制&#xff0c;本章将讲述下编辑器的另一种绘制方式&#xff1a;区域绘制。 1、区域绘制功能简介 在场景中绘制资产时&#xff0c;除使用上述两个的方式外&#xff0c;NSDT 编辑器还支持使用区域绘制的方式进行绘制。先选取需要…

【C/C++笔试练习】——数组名和数组名、switch循环语句、数据在计算机中的存储顺序、字符串中找出连续最长的数字串、数组中出现次数超过一半的数字

文章目录 C/C笔试练习1.数组名和&数组名&#xff08;1&#xff09;数组名和&数组名的差异&#xff08;2&#xff09;理解数组名和指针偏移&#xff08;3&#xff09;理解数组名代表的含义&#xff08;4&#xff09;理解数组名代表的含义 2.switch循环语句&#xff08;6…

FFmpeg 命令:从入门到精通 | ffplay 简单过滤器

FFmpeg 命令&#xff1a;从入门到精通 | ffplay 简单过滤器 FFmpeg 命令&#xff1a;从入门到精通 | ffplay 简单过滤器视频旋转视频反转视频旋转和反转音频变速播放视频变速播放音视频同时变速更多参考 FFmpeg 命令&#xff1a;从入门到精通 | ffplay 简单过滤器 本节介绍了简…

【CFD小工坊】浅水方程的离散及求解方法

【CFD小工坊】浅水方程的离散及求解方法 前言基于有限体积法的方程离散界面通量与源项计算干-湿网格的处理数值离散的稳定性条件参考文献 前言 我们模型的控制方程&#xff0c;即浅水方程组的表达式如下&#xff1a; ∂ U ∂ t ∂ E ( U ) ∂ x ∂ G ( U ) ∂ y S ( U ) U…

十五、异常(4)

本章概要 Java 标志异常 特例&#xff1a;RuntimeException 使用 finally 进行清理 finally 用来做什么&#xff1f;在 return 中使用 finally缺憾&#xff1a;异常丢失 Java 标准异常 Throwable 这个 Java 类被用来表示任何可以作为异常被抛出的类。Throwable 对象可分为两…

JUC——并发编程—第二部分

集合类不安全 list不安全 //报错 java.util.ConcurrentModificationException public class ListTest {public static void main(String[] args) {List<String> list new CopyOnWriteArrayList<>();//并发下Arrayist边读边写会不安全的/*** 解决方案&#xff1a…

国庆作业 9月30 消息队列实现进程间通信

01_write.c&#xff1a; #include <myhead.h> #define MAX 1024//x消息结构体 typedef struct {long msgtype; //消息类型char msg[MAX]; //消息正文 }Msg;#define SIZE sizeof(Msg)-sizeof(long) //正文大小int main(int argc, const char *argv[]) {//1:创建一个key…

机器学习之单层神经网络的训练:增量规则(Delta Rule)

文章目录 权重的调整单层神经网络使用delta规则的训练过程 神经网络以权值的形式存储信息,根据给定的信息来修改权值的系统方法称为学习规则。由于训练是神经网络系统地存储信息的唯一途径&#xff0c;因此学习规则是神经网络研究中的一个重要组成部分 权重的调整 &#xff08…

企业级磁盘阵列存储系统由硬到软全析

企业级磁盘阵列是由一组设备构成的存储系统,主要包括两种类型的设备,分别是控制器和扩展柜,其中控制器只有一台,扩展柜可以没有,也可以有多台。在EMC的Unity中分别称为DPE(Disk Processor Enclosure)和DAE(Disk Array Enclosure),在华为的OceanStor里面称为控制框和硬…

【网络模型】OSI七层网络模型、TCP/IP网络模型、键入网址到页面显示的过程、DNS是什么等重点知识汇总

目录 OSI 的七层模型 TCP/IP 网络模型 键入网址到网页显示发生了什么 你知道DNS是什么&#xff1f; OSI 的七层模型 简要概括 应用层&#xff1a;为用户的应用进程提供网络通信服务表示层&#xff1a;处理用户信息的表示问题&#xff0c;数据的编码&#xff0c;压缩和解压…

在枚举类中“优雅地”使用枚举处理器

使用枚举类的一大好处就是&#xff0c;代码易懂&#xff0c;方便自己或他人维护。如&#xff0c;枚举状态、异常等。 下面有两个类&#xff08;枚举类和实体类&#xff09;&#xff1a; package com.zhang.enums;import lombok.Getter;/*** Author lgz* Description* Date 202…

【生物信息学】基因差异分析Deg(数据读取、数据处理、差异分析、结果可视化)

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 3. IDE 三、实验内容 0. 导入必要的工具包 1. 定义一些阈值和参数 2. 读取数据 normal_data.csv部分展示 tumor_data.csv部分展示 3. 绘制箱型图 4. 删除表达量低于阈值的基因 5. 计算差异显著的基…

Git多账号管理通过ssh 公钥的方式,git,gitlab,gitee

按照目前国内访问git&#xff0c;如果不科学上网&#xff0c;我们很大可能访问会超时。基于这个&#xff0c;所以我现在的git 配置已经增加到了3个了 一个公司gitlab&#xff0c;一个git&#xff0c;一个gitee. 以下基于这个环境&#xff0c;我们来说明下如何创建配置ssh公钥。…

VBA技术资料MF63:遍历形状并改变颜色

【分享成果&#xff0c;随喜正能量】人生&#xff0c;一站有一站的风景&#xff0c;一岁有一岁的味道&#xff0c;你的年龄应该成为你生命的勋章而不是你伤感的理由。生活嘛&#xff0c;慢慢来&#xff0c;你又不差&#xff01;。 我给VBA的定义&#xff1a;VBA是个人小型自动…

【数据结构与算法】栈与队列相关算法的实现

目录 检查括号是否成对出现 反转字符串 循环队列的实现 使用队列实现栈 使用栈实现队列 检查括号是否成对出现 算法要求 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串&#xff0c;判断该字符串是否有效。 有效字符串需满…

树莓派基本配置(2)

安装motion $sudo apt-get update $sudo apt-get install motion配置motion sudo nano /etc/default/motionsudo nano /etc/motion/motion.conf主要改这些参数 //让Motion作为守护进程运行 daemon on ... //用这个端口号来读取数据 stream_port 8081 ... //网络上其它主机…

2023年上海市安全员B证证模拟考试题库及上海市安全员B证理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年上海市安全员B证证模拟考试题库及上海市安全员B证理论考试试题是由安全生产模拟考试一点通提供&#xff0c;上海市安全员B证证模拟考试题库是根据上海市安全员B证最新版教材&#xff0c;上海市安全员B证大纲整理…