Linux进阶-ipc消息队列

news2024/11/25 21:44:31

目录

system-V IPC

消息队列

消息队列和信号管道的对比

消息队列和信号的对比

消息队列和管道的对比

消息队列函数API

msgget():打开或创建消息队列

msgsnd():发送消息

msgrcv():接收消息

msgctl():控制消息队列

msgsnd.c文件

msgrcv.c文件

Makefile文件

执行过程


system-V IPC

system-V IPC消息队列共享内存信号量

这些对象的操作接口都类似,在系统中都使用key的键值来唯一标识,而且都是持续性资源(即它们被创建后不会因为进程的退出而消失,而会持续性存在,除非调用特殊的函数或命令删除它们)。

Linux的IPC对象在内核内部使用链表维护,不同的对象使用IPC标识符来标识(如消息队列标识符msqid共享内存标识符shmid信号量标识符semid)。

对于用户而言,内核提供了简洁的接口,不同的进程通过IPC关键字(key)即可访问具体的对象。

ipcs:查看系统当前IPC对象。

消息队列

信号队列从一个进程发送一个数据块到另一个进程每个数据块含有一个类型接收进程可以独立地接收含有不同类型的数据结构

消息队列和信号管道的对比

消息队列和信号的对比

信号承载的信息量少,而消息队列可以承载大量自定义的数据。

消息队列和管道的对比

消息队列和有名管道都可以在不相关的进程间通信,同时都是通过发送和接收的方式来传递数据。

        有名管道:发送数据使用write()函数、接收数据使用read()函数。

        消息队列:发送数据使用msgsnd()函数、接收数据使用msgrcv()函数。消息队列对每个数据都有一个最大长度的限制。

消息队列也可以独立于发送和接收进程而存在,在进程终止时,消息队列及其内容并不会被删除。

管道只能承载无格式字节流,而消息队列提供有格式的字节流,可以减少开发人员的工作量。

消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级,接收程序可以通过消息类型有选择地接收数据,而不像有名管道只能默认接收。

消息队列可以实现消息的随机查询,消息不一定要以先进先出的顺序接收,也可以按消息的类型接收。

消息队列函数API

msgget():打开或创建消息队列

收发消息需要具体的消息队列对象,函数作用就是创建或获取一个消息队列对象,并返回消息队列标识符。创建的消息队列的数量受到系统可支持的消息队列数量的限制。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
/*
key:消息队列的关键字值,多个进程可以通过它访问同一个消息队列。例如收发进程都使用。有个特殊值IPC_PRIVATE,用于创建当前进程的私有消息队列。
msgflg:表示创建的消息队列的模式标志参数,主要有IPC_CREAT,IPC_EXCL和权限mode。
    如果IPC_CREAT为真:如果内核中不存在关键字与key相等的消息队列,则新建一个消息队列;如果存在,返回此消息队列的标识符
    如果IPC_CREAT | IPC_EXCL为真:如果内核中不存在关键字与key相等的消息队列,则新建一个消息队列;如果存在,则报错
    mode指IPC对象存取权限。如0666等
返回值:
    执行成功:队列ID
    执行失败:-1,并且错误原因存于error
*/

权限只有读写,没有执行

当key被指定为IPC_PRIVATE,系统会自动产生一个未用的key来对应一个新的消息队列对象,这个消息队列一般用于进程内部间通信

该函数可能返回以下错误代码error:

        EACCES:指定的消息队列已存在,但调用进程没有权限访问它

        EEXIST:key指定的消息队列已存在,而msgflg同时指定IPC_CREAT | IPC_EXCL标志

        ENOENT:key指定的消息队列不存在,同时msgflg没有指定IPC_CREAT标志

        ENOMEM:需要建立消息队列,但内存不足

        ENOSPC:需要建立消息队列,但已达到系统的限制

msgsnd():发送消息

msgsnd()函数把消息发送到已打开的消息队列的末尾。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
/*
msqid:消息队列标识符
msgp:发送给队列的消息。可以是任何类型的结构体,但第一个字段必须为long类型(即表明此发送消息的类型),如下结构体
msgsz:待发送消息的大小,不包含消息类型占用的4个字节(即下面结构体的mtext的长度)
msgflg:
    0:当消息队列满时,该函数会阻塞,直到消息能写入消息队列
    IPC_NOWAIT:当消息队列满时,该函数不等待立即返回
    IPC_NOERROR:要发送的消息大于size字节,则把消息截断,截断部分将被丢弃,且不通知发送进程
返回值:
    执行成功:0
    执行失败:-1,并且错误原因存于error
*/
/* msgp定义的参数格式 */
struct s_msg{
    long type;        /* 消息类型,必须大于0 */
    char mtext[1];    /* 消息正文,可以是其他任何类型 */
}msgp;

msgsnd()为阻塞函数,解除阻塞的条件:

        消息队列有容乃该消息的空间

        msqid代表的消息队列被删除

        调用msgsnd函数的进程被信号中断

该函数可能返回以下错误代码error:

        EAGAIN:参数msgflg设为IPC_NOWAIT,而消息队列已满

        EIDRM:msqid标识符的消息队列已被删除

        EACCESS:无权限写入消息队列

        EFAULT:参数msgp指向无效的内存地址

        EINTR:队列已满而处于等待情况下被信号中断

        EINVAL:无效的参数msqid、msgsz或参数消息类型type小于0

msgrcv():接收消息

msgrcv()函数把消息从消息队列取出(可以指定取出某一条消息),即从msqid标识符的消息队列读取消息并将消息存储在msgp中,读取后把此消息从消息队列中删除。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
/*
msqid:消息队列标识符
msgp:发送给队列的消息。可以是任何类型的结构体,但第一个字段必须为long类型(即表明此发送消息的类型)
msgsz:待发送消息的大小,不包含消息类型占用的4个字节
msgtyp:
    0:接收第一个消息
    >0:接收类型等于msgtyp的第一个消息
    <0:接收类型等于或小于msgtyp绝对值的第一个消息
msgflg:
    0:阻塞式接收消息,没有该类型的消息时该函数一直会阻塞等待
    IPC_NOWAIT:若消息队列中没有相应类型的消息可以接收,则函数error为ENOMSG
    IPC_EXCEPT:与msgtype配合使用返回队列第一个类型不为msgtype的消息
    IPC_NOERROR:若队列中满足条件的消息内容大于所请求的size字节,则把该消息截断,截断部分将被丢弃
返回值:
    执行成功:实际读取到的消息数据长度
    执行失败:-1,并且错误原因存于error
*/

msgrcv()为阻塞函数,解除阻塞的条件:

        消息队列中有了满足条件的消息

        msqid代表的消息队列被删除

        调用msgrcv()函数的进程被信号中断

该函数可能返回以下错误代码error:

        E2BIG:消息数据长度大于msgsz而msgflag没有设置IPC_NOERROR

        EIDRM:msqid标识符的消息队列已被删除

        EACCESS:无权限读取消息队列

        EFAULT:参数msgp指向无效的内存地址

        ENOMSG:参数msgflg设为IPC_NOWAIT,而消息队列中无消息可读

        EINTR:等待读取队列内的消息情况下被信号中断

msgctl():控制消息队列

msgctl()可以操作消息队列,如设置或者获取消息队列的相关属性。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
/*
msqid:消息队列标识符
cmd:
    IPC_STAT:获取该msg的信息,保存在结构体msqid_ds类型的buf中
    IPC_SET:设置消息队列的属性,要设置的属性需先存储在结构体msqid_ds类型的buf中,可设置的属性包括msg_perm.uid、msg_perm.gid、msg_perm.mode和msg_qbytes。
    IPC_RMID:立即删除该msg,并且唤醒所有阻塞在该msg上的进程,同时忽略第三个参数
    IPC_INFO:获得关于当前系统中msg的限制值信息
    MSG_INFO:获得关于当前系统中msg的相关资源消耗信息
    MSG_STAT:同IPC_STAT,但msgid为该消息队列在内核中记录所有消息队列信息的数组的下标,因此通过迭代所有的下标可以获得系统中所有消息队列的相关消息
返回值:
    执行成功:0
    执行失败:-1,并且错误原因存于error
*/

该函数可能返回以下错误代码error:

        EACCESS:cmd参数为IPC_STAT,却无权限读取该消息队列

        EFAULT:buf参数指向无效的内存地址

        EIDRM:msqid标识符的消息队列已被删除

        EINVAL:无效的参数msqid、cmd

        EPERM:cmd参数为IPC_SET | IPC_RMID,却无权限执行

msgsnd.c文件

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

#define BUFFER_SIZE     512

typedef struct message{
        long msg_type;
        char msg_text[BUFFER_SIZE];
}message;

int main(void)
{
        int qid;
        message msg;

        if((qid = msgget((key_t)1234, IPC_CREAT|0666)) == -1){
                perror("msgget\n");
                exit(1);
        }

        printf("open queue %d\n", qid);

        while(1){
                printf("Enter some message to the queue:");
                if((fgets(msg.msg_text, BUFFER_SIZE, stdin)) == NULL){
                        printf("get message end\n");
                        exit(1);
                }

                msg.msg_type = getpid();

                if((msgsnd(qid, &msg, strlen(msg.msg_text), 0)) < 0){
                        perror("msgsnd");
                        exit(1);
                }else{
                        printf("send message\n");
                }

                if(strncmp(msg.msg_text, "quit", 4) == 0){
                        printf("quit get message\n");
                        break;
                }
        }

        exit(0);
}

msgrcv.c文件

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

#define BUFFER_SIZE     512

typedef struct message{
        long msg_type;
        char msg_text[BUFFER_SIZE];
}message;

int main(void)
{
        int qid;
        message msg;

        if((qid = msgget((key_t)1234, IPC_CREAT|0666)) == -1){
                perror("msgget\n");
                exit(1);
        }

        printf("open queue %d\n", qid);

        do{
                memset(msg.msg_text, 0, BUFFER_SIZE);

                if(msgrcv(qid, (void *)&msg, BUFFER_SIZE, 0, 0) < 0){
                        perror("msgrcv");
                        exit(1);
                }

                printf("the message from process %ld:%s", msg.msg_type, msg.msg_text);
        }while(strncmp(msg.msg_text, "quit", 4));

        if((msgctl(qid, IPC_RMID, NULL)) < 0){
                perror("msgctl");
                exit(1);
        }else{
                printf("Delete msg qid:%d\n", qid);
        }

        exit(0);
}

Makefile文件

为两个工程,但都类似,照旧。

执行过程

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

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

相关文章

移动互联网客户端可能没什么路可走了.......

2010~2020可以算移动客户端的黄金十年了&#xff0c;微信、淘宝、抖音等国民级应用都诞生于这十年间&#xff0c;也顺带产生了不少技术上的黑科技&#xff08;比如动态化、跨平台、热修复&#xff09;。 然而现在头部公司的稳定&#xff0c;App独立生存的空间被不断挤压&#…

el-menu页面离开弹窗,当前激活菜单的高亮问题

问题描述 在A页面监控路由离开&#xff0c;&#xff0c;弹出弹窗后提示未保存点击取消&#xff0c;此时左侧的菜单激活是B高亮&#xff0c;正常应该是激活A菜单。 1&#xff0c;A页面页面离开的弹窗&#xff0c;在A页面弹窗点击取消 ##解决方法 1.在菜单组件增事件&#xf…

75.C++ STL queue容器

目录 1.什么是queue容器 2.queue的构造函数 3.存取、插入、删除操作 4.赋值操作 5.大小操作 以下是一个简单示例&#xff0c;演示如何使用 queue&#xff1a; 1.什么是queue容器 queue 是 C 标准库提供的队列容器&#xff0c;它是一个容器适配器&#xff0c;用于管理遵循…

如何管理前端状态?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

如何清理内存空间?几步操作轻松搞定!

电脑内存的清理是维护系统性能的重要步骤之一。如果电脑内存不足&#xff0c;可能会导致电脑运行卡顿、无法存入文件等各种问题。及时清理电脑内存非常重要。怎样清理电脑内存呢&#xff1f;怎么才能更高效的释放更多电脑内存呢&#xff1f;下面是三个常用的方法。 一、关闭不必…

实施03(文件夹共享和网络配置)

远程连接&#xff08;防火墙设置&#xff09;把远程端口打开新建规则 选择端口后&#xff0c;选择TCP&#xff0c;选择特定本地端口&#xff0c;输入我们需要开放的端口号下一步选择允许连接回车给开放的端口号取个名称回车就可以了 实现文件夹共享首先在任意盘符新建一个文件夹…

工控网络协议模糊测试:用peach对modbus协议进行模糊测试

0x00 背景 本人第一次在FB发帖&#xff0c;进入工控安全行业时间不算很长&#xff0c;可能对模糊测试见解出现偏差&#xff0c;请见谅。 在接触工控安全这一段时间内&#xff0c;对于挖掘工控设备的漏洞&#xff0c;必须对工控各种协议有一定的了解&#xff0c;然后对工控协议…

攀岩绳上亚马逊合规认证EN892测试标准

攀岩绳 攀岩绳是与攀岩安全带和锚点相连的一种装备&#xff0c;用于保护攀岩者&#xff0c;使其不会从高处跌落。攀岩绳由承重内芯和围绕内芯编织的护套组成。 亚马逊关于攀岩绳的政策 根据亚马逊的要求&#xff0c;所有攀岩绳均应经过检测&#xff0c;并且符合下列特定法规或…

Go语言Gin框架中使用MySQL数据库的三种方式

文章目录 原生SQL操作XORMGORM 本文演示在Gin框架中通过三种方式实现增删改查的操作&#xff0c;数据表结构如下&#xff1a; CREATE TABLE users (id int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT ID,user_no bigint(20) unsigned NOT NULL COMMENT 用户编号,name varch…

Ansible --- playbook 剧本

一、playbook 的简介 playbook是 一个不同于使用Ansible命令行执行方式的模式&#xff0c;其功能更强大灵活。 简单来说&#xff0c;playbook是一个非常简单的配置管理和多主机部署系统&#xff0c; 不同于任何已经存在的模式&#xff0c;可作为一个适合部署复杂应用程序的基…

win11 定时计划任务

控制面板 任务计划 添加任务计划 &#xff0c;选按步骤添加。

2023年【天津市安全员C证】模拟考试及天津市安全员C证实操考试视频

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 天津市安全员C证模拟考试是安全生产模拟考试一点通生成的&#xff0c;天津市安全员C证证模拟考试题库是根据天津市安全员C证最新版教材汇编出天津市安全员C证仿真模拟考试。2023年【天津市安全员C证】模拟考试及天津市…

docker全家桶(基本命令、dockerhub、docker-compose)

概念 应用场景&#xff1a; Web 应用的自动化打包和发布。自动化测试和持续集成、发布。在服务型环境中部署和调整数据库或其他的后台应用。从头编译或者扩展现有的 OpenShift 或 Cloud Foundry 平台来搭建自己的 PaaS 环境。 作用&#xff1a;Docker 使您能够将应用程序与基…

算法通关村第19关【青铜】| 动态规划

动态规划&#xff08;Dynamic Programming&#xff0c;简称DP&#xff09;是一种解决多阶段决策过程最优化问题的数学方法。它通常用于解决那些具有重叠子问题和最优子结构性质的问题&#xff0c;这些问题可以分解为多个相互关联的子问题。 动态规划的核心思想是将原问题分解为…

Android查看签名信息系列 · 使用逆向分析工具JadxGUI获取签名

前言 Android查看签名信息系列之使用逆向分析工具JadxGUI获取签名&#xff0c;通过这种方式&#xff0c;可以获取到的签名信息包括&#xff1a;MD5、SHA1、SHA-256、公钥(模数)等信息 实现方法 1、进入JadxGUI目录下的lib文件夹内&#xff0c;找到jadx-gui-1.4.7.jar文件 2、…

医疗制药行业数字化创新实践

本文将为大家分享3个制药行业的创新案例吧&#xff0c;都是在不同智能制造落地场景下的典型案例&#xff0c;希望对大家有所启发。 01 医疗设备企业零代码搭建集成式信息化管理平台&#xff0c;年节省150余万元 医疗制药行业数字化实现工具>>>>https://www.jianda…

LLVM(6)ORC实例分析:Transform in cpp

Transform用例总结 该用例调用JIT的setTransform接口&#xff0c;传入pass对IR代码做了一系列优化。优化一&#xff1a;fac函数的调用者能直接拿到返回值&#xff0c;不在需要进入fac计算了。 正常函数调用a fac(5)需要进入fac函数后才能拿到结果120。transform后&#xff0c…

java部署教程

关闭防火墙 不管是windows还是linux&#xff0c;首先必须关闭防火墙。 # linux添加8080端口 firewall-cmd --zonepublic --add-port8080/tcp --permanent#删除80端口 firewall-cmd --zonepublic --remove-port8080/tcp --permanent# 刷新使端口立即生效 firewall-cmd --reloa…

AI大模型下一步怎么走?百度携AI原生应用抢先作答

前言 10月17日&#xff0c;百度世界2023在北京首钢园召开&#xff0c;这是百度近四年来首次恢复线下举办世界大会&#xff0c;会上发布了文心大模型4.0以及基于大模型的AI原生应用的最新进展。 文章目录 前言我眼里的百度世界大会文心大模型4.0正式发布&#xff0c;与GPT4相比毫…

解决spring项目中无法加载resources下文件

解决spring项目中无法加载resources下文件 问题发现问题解决步骤一&#xff1a;检查文件名步骤二&#xff1a;确保测试资源目录步骤三&#xff1a;检查文件路径是否正确 问题发现 在学习Spring过程中&#xff0c;TestContext框架试图检测一个默认的XML资源位置。如果您的类被命…