Linux应用编程---9.消息队列

news2024/11/19 4:40:50

Linux应用编程—9.消息队列

​ 消息队列用于进程之间的通讯,可以在如父子进程、兄弟进程这样的具有亲缘关系的进程之间传递数据,也可以用于具有非亲缘关系的进程之间通讯。消息队列可以传递结构体,所以可以发送任意数据类型。与消息队列有关的函数分别是:创建、发送、接收与删除。

9.1 创建消息队列msgget()

​ Linux终端下输入:man msgget,如图1所示。

image-20221202141039518

图1 msgget函数详情
NAME
       msgget - get a System V message queue identifier

SYNOPSIS
       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>

       int msgget(key_t key, int msgflg);

​ msgget()获取一个System v下的消息队列标识符。函数原型为:int msgget(key_t key, int msgflg);需要包含头文件:sys/msg.h。

DESCRIPTION
       The  msgget() system call returns the System V message queue identifier associated with the value of the key argument.  It may be used either to obtain the identifier of
       a previously created message queue (when msgflg is zero and key does not have the value IPC_PRIVATE), or to create a new set.

       A new message queue is created if key has the value IPC_PRIVATE or key isn't IPC_PRIVATE, no message queue with the given key key exists, and IPC_CREAT is  specified  in
       msgflg.

       If  msgflg specifies both IPC_CREAT and IPC_EXCL and a message queue already exists for key, then msgget() fails with errno set to EEXIST.  (This is analogous to the ef‐
       fect of the combination O_CREAT | O_EXCL for open(2).)

       Upon creation, the least significant bits of the argument msgflg define the permissions of the message queue.  These permission bits have the same format  and  semantics
       as the permissions specified for the mode argument of open(2).  (The execute permissions are not used.)

       If a new message queue is created, then its associated data structure msqid_ds (see msgctl(2)) is initialized as follows:

              msg_perm.cuid and msg_perm.uid are set to the effective user ID of the calling process.

              msg_perm.cgid and msg_perm.gid are set to the effective group ID of the calling process.

              The least significant 9 bits of msg_perm.mode are set to the least significant 9 bits of msgflg.

              msg_qnum, msg_lspid, msg_lrpid, msg_stime, and msg_rtime are set to 0.

              msg_ctime is set to the current time.

              msg_qbytes is set to the system limit MSGMNB.

       If the message queue already exists the permissions are verified, and a check is made to see if it is marked for destruction.

​ 描述:msgget()系统调用返回与key参数值相关的System v消息队列标识符。既可以用于获取先前创建的消息队列的标识符(当msgflg为零且key没有值IPC_PRIVATE时),也可以用于创建一个新的集合。

​ 如果key的值为:IPC_PRIVATE或者不是IPC_PRIVATE,一个新的消息队列将被创建。不存在给定key值的消息队列,并且IPC_CREAT是特殊的标志位。

​ 如果msgflg同时指定了IPC_CREAT与IPC_EXCL,并且key值的消息队列已经存在,那么msgget()将失败。

RETURN VALUE
       If successful, the return value will be the message queue identifier (a nonnegative integer), otherwise -1 with errno indicating the error.

​ 函数返回值,如果成功的话,返回消息队列标识符,失败则返回-1。

9.2 发送与接收消息队列msgsnd()、msgrcv()

​ Linux终端下输入:man msgsnd,如图2所示。

image-20221202143242346

图2 msgsnd()函数详情
NAME
       msgrcv, msgsnd - System V message queue operations

SYNOPSIS
       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>

       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);

​ msgrcv()与msgsnd()用于System v下消息队列操作。发送消息队列函数原型为: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)。

DESCRIPTION
       The msgsnd() and msgrcv() system calls are used to send messages to, and receive messages from, a System V message queue.  The calling process must have write permission
       on the message queue in order to send a message, and read permission to receive a message.

       The msgp argument is a pointer to a caller-defined structure of the following general form:

           struct msgbuf {
               long mtype;       /* message type, must be > 0 */
               char mtext[1];    /* message data */
           };

       The mtext field is an array (or other structure) whose size is specified by msgsz, a nonnegative integer value.  Messages of zero length (i.e., no mtext field) are  per‐
       mitted.   The mtype field must have a strictly positive integer value.  This value can be used by the receiving process for message selection (see the description of ms‐
       grcv() below).

​ msgsnd()与msgrcv()函数系统调用被用于发送或者接收System v消息队列中的消息。调用进程对于消息队列必须要有写权限目的是为了发送消息,和读权限为了读取消息。

​ 参数msgp是一个指针,指向如下面类型的结构体。mtext是一个数组或者其它类型,大小是msgsz,是一个无符号整形。mtype参数必须有一个确切的正整数,这个值被用于通过接收进程的消息选择。对于msgsnd()的参数,msgid是消息队列创建时返回的id号,msgsz是发送往消息队列数据的大小,msgflg是标志位,一般默认标志位,填写入0即可。

​ msgrcv(),ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);msgid是消息队列标识符,创建时会得到;msgp是指向结构体的指针,msgsz是消息队列内数据的大小,与发送往消息队列数据大小一致;msgtyp用于接收消息时消息选择,发送和接收进程往消息队列里发送的数据靠msgtyp联系,如果这个两个不一样,则接收进程获取不到消息队列里的消息;msgflg为标志位,一般默认标志位,写0即可。

9.3 消息队列实践-父子进程间通讯

​ 先创建一个消息队列,然后创建消息队列数据结构体,成员分别是消息队列类型mtype、用来存储字符串的数组mtetx[32],整数型数据num。然后创建父子进程,在父进程中,通过gets()函数获取用户输入字符串;通过scanf()函数获取用户输入的数字,将数据保存在结构体内,调用msgsnd()函数发送,发送后调用waitpid()等待子进程接收消息队列数据、打印并且结束进程,子进程调用msgrcv()函数接收消息队列里的数据。

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

#define MY_TYPE 9527

int main(void)
{
        pid_t pid;
        int msgid = 0;

        typedef struct
        {
                long mtype;
                char mtext[32];
                int num;
        }msgbuf_TypeDef;

        msgbuf_TypeDef msgbuf;

        msgid = msgget(IPC_PRIVATE, IPC_CREAT);
        if(-1 == msgid)
                perror("msgget.");

        pid = fork();

        if(pid > 0)
        {
                sleep(5);

                msgbuf.mtype = MY_TYPE;
                printf("Please enter a string you want to send:\n");
                gets(msgbuf.mtext);
                printf("Please enter a number you want to send:\n");
                scanf("%d", &msgbuf.num);

                msgsnd(msgid, &msgbuf, sizeof(msgbuf) - sizeof(msgbuf.mtype), 0);

                waitpid(pid, NULL, 0);
        }
        else if(pid == 0)
        {
                printf("Child process receiving data from msg:\n");
                msgrcv(msgid, &msgbuf, sizeof(msgbuf) - sizeof(msgbuf.mtype), MY_TYPE, 0);
                printf("The data is %s, %d.\n", msgbuf.mtext, msgbuf.num);

                msgctl(msgid, IPC_RMID, 0);
        }
        else
                perror("fork.");


        return 0;
}

​ 运行结果:

image-20221202213420263

图3 运行结果
​ 代码异常现象:子进程中的消息队列接收函数,并没有阻塞式接收,等到消息队列发送函数。而是接收了一个消息队列中的消息,并且打印了 出来。这个值是内存中的随机值。

image-20221211120843314

图4 异常运行结果

​ 原因是,没有启用超级权限模式。代码运行前,输入:su。在root权限下操作。

9.4 非亲缘进程间通讯

​ 程序流程图如下图5所示。

image-20221211162628307

​ 消息队列发送端代码。

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

#define MY_TYPE 1314
#define USER_KEY 9527

int main(void)
{

        int msgid;

        typedef struct msg
        {
                long mtype;
                char mtext[32];
                int number;
        }msgbuf_TypeDef;

        msgbuf_TypeDef msgbuf;

        msgid = msgget(USER_KEY, IPC_CREAT);

        if(-1 == msgid)
                perror("msgget.");

        msgbuf.mtype = MY_TYPE;
        printf("Please enter a strings you want to send.\n");
        gets(msgbuf.mtext);
        printf("Please enter a number you want to send.\n");
        scanf("%d", &msgbuf.number);

        msgsnd(msgid, &msgbuf, sizeof(msgbuf) - sizeof(msgbuf.mtype), 0);


        return 0;
}

​ 消息队列接收端代码。

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

#define MY_TYPE 1314
#define USER_KEY 9527

int main(void)
{

        int msgid;

        typedef struct msg
        {
                long mtype;
                char mtext[32];
                int number;
        }msgbuf_TypeDef;

        msgbuf_TypeDef msgbuf;

        msgid = msgget(USER_KEY, IPC_CREAT);

        if(-1 == msgid)
                perror("msgget.");

        while(1)
        {
                printf("Wtatting mesages from another process.\n");
                msgrcv(msgid, &msgbuf, sizeof(msgbuf) - sizeof(msgbuf.mtype), MY_TYPE, 0);
                printf("datas is %s %d.\n", msgbuf.mtext, msgbuf.number);
        }


        return 0;
}

​ 消息队列发送端代码运行结果:

root@ubuntu:/home/sgk/Documents/Linux_Program/no_relation_msg# ./send
Please enter a strings you want to send.
Hello world.
Please enter a number you want to send.
12345
root@ubuntu:/home/sgk/Documents/Linux_Program/no_relation_msg# 

​ 消息队列接收端代码运行结果:

root@ubuntu:/home/sgk/Documents/Linux_Program/no_relation_msg# ./recv
Wtatting mesages from another process.
datas is Hello world. 12345.
Wtatting mesages from another process.

9.5 总结

​ 消息队列可以用于亲缘关系间的进程通讯,也可以用于具有非亲缘关系间的进程之间通讯。通讯过程分为大致4步骤:1 创建消息队列结构体,使用msgget()创建消息队列;2 使用msgsnd()发送填充过数据的消息队列结构体;3 使用msgrcv()函数接收;4 如果不在使用,则使用msgctl()函数删除创建的消息队列。
在这里插入图片描述

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

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

相关文章

数据结构(一)——链表

链表与邻接表 介绍 链表作为一种基础数据结构&#xff0c;具有几个特点&#xff1a; 优点&#xff1a;插入、删除非常快&#xff08;需要知道需要插入和删除节点前一个位置&#xff09;缺点&#xff1a;查询、访问&#xff08;用索引&#xff09;非常的慢 链表的创建方法一…

Selenium用法详解【cookies操作】【JAVA爬虫】

简介本文主要讲解java代码利用Selenium控制浏览器获取网站的cookies,对网站cookies的相关操作教程。cookies操作cookies 是识别用户登录与否的关键&#xff0c;爬虫中常常使用 selenium jsoup 实现 cookie持久化&#xff0c;即先用 selenium 模拟登陆获取 cookie &#xff0c;…

你可能从未想过的:人工智能未来50年的安全领域问题

前言 随着人工智能技术的普及和发展&#xff0c;很多人工智能出现的故障和问题也会愈发明显。本文简单讲述了未来50年人工智能发展过程中可能会出现的景象和问题。 一、人工智能独立 尽管很可能第一批人工智能是由人类发明制作的&#xff0c;但随着大量基础设施的完善&#x…

javaweb-会话技术CookieSession

文章目录会话技术Cookie&Session1&#xff0c;会话跟踪技术的概述2&#xff0c;Cookie2.1 Cookie的基本使用2.2 Cookie的原理分析2.3 Cookie的使用细节2.3.1 Cookie的存活时间2.3.2 Cookie存储中文3&#xff0c;Session3.1 Session的基本使用3.2 Session的原理分析3.3 Sess…

4.8、网际控制报文协议 ICMP

为了更有效地转发 IP 数据报和提高交付成功的机会 在网际层使用了网际控制报文协议 ICMP(Internet Control Message Protocol)。 主机或路由器使用 ICMP 来发送 差错报告报文\color{red}差错报告报文差错报告报文和询问报文\color{red}询问报文询问报文。 ICMP报文被封装在IP…

基于采样的规划算法之动态窗口法(DWA)

动态规划将一个多步决策问题拆分成若干子问题,并且保证子问题的最优解能推出完整问题的最优解。所以,动态规划可以得到采样空间下的最优路径解。本章介绍的动态窗口法(Dynamic Window Approach, DWA)与动态规划类似,也是将从起点到终点的多步决策问题拆分成一系列子问题—…

Linux应用编程---1.线程与进程

Linux应用编程—1.线程与进程 1 重要概念 1.1 程序 ​ 程序指的是还没有运行起来的源代码&#xff0c;比如电脑上安装的“Keil MDK”、“Xshell”等等。 1.2 进程 ​ Win10环境下&#xff0c;打开任务管理器&#xff0c;能看到有“进程”一栏&#xff0c;点击进去能看到5个…

2023 Real World CTF体验赛部分Writeup

web1 Thinkphp lang多语言 RCE漏洞&#xff0c;直接打 GET /index.php?config-create/<?eval($_REQUEST[1]);?>/tmp/keep.php HTTP/1.1 Host: 47.98.124.175:8080 Cache-Control: max-age0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; …

QT-5.12: QSqlDatabase: QMYSQL driver not loaded 错误及解决方案

错误现象及原因&#xff1a; &#xff08;1&#xff09;qt SQL模块已默认不编译mysql驱动&#xff0c;导致mysql驱动缺失&#xff0c;错误提示如下&#xff08;可用数数据库驱动不含mysql驱动&#xff0c;执行方法一和二&#xff09;&#xff1b; &#xff08;2&#xff09;已…

C++新基础类型long long, char8_t, char16_t, char32_t

C新基础类型long long, char8_t, char16_t, char32_t一、整数类型 long long二、新字符类型 char16_t 和 char32_t三、char8_t 字符类型一、整数类型 long long 我们知道long通常表示一个32位整型&#xff0c;而long long则是用来表示一个64位的整型。 C标准中定义&#xff0…

vue3包依赖关系

包reactivity &#xff1a;响应式API&#xff0c;例如toRef、reactive、Effect、computed、watch等&#xff0c;可作为与框架无关的包&#xff0c;独立构建runtime-core&#xff1a;平台无关的运行时核心代码。包括虚拟dom渲染、组件实现和JavaScript API。可以使用这个包针对特…

机器学习实战教程(十一):线性回归基础篇

一、前言前面的文章介绍了很多分类算法&#xff0c;分类的目标变量是标称型数据&#xff0c;而本文将会对连续型的数据做出预测。主要讲解简单的线性回归和局部加权线性回归&#xff0c;并通过预测鲍鱼年龄的实例进行实战演练。二、什么是回归&#xff1f;回归的目的是预测数值…

Java学习笔记——继承(下)

目录继承中构造方法的访问特点构造方法的访问特点-父类没有空参构造方法代码优化和内存图解xx信息管理系统-集成改进抽象类入门抽象类的注意事项模板设计模式final关键字xx信息管理系统——抽象类改进代码块xx信息管理系统-代码块改进继承中构造方法的访问特点 子类再初始化之…

汽车电子行业入门指南「2022年国内主要新能源车销量」

汽车电子行业入门指南 雪云飞星 2022年国内主要新能源车销量 2022年汽车行业内的人们可谓是经历了很多&#xff1a;4月上海疫情、华为携问界的强势入局、年底取消新能源免购置税等等。对于博主而言也算人生一个小阶段&#xff0c;年底离开了曾经奋斗的某为&#xff0c;翻开了…

序列傅里叶变换

序列傅里叶变换定义 序列傅里叶变换 (DFT) 是一种数学变换&#xff0c;它将一个有限长度的序列转换为其频谱表示。它使用一个复数数组表示序列的频谱&#xff0c;其中每个元素表示对应的频率成分的幅度和相位。 DFT 的公式为&#xff1a; X[k] ∑n0 to N-1 x[n] * e^(-j2πkn/…

Unreal UCLASS常用的类标记宏

BlueprintType,使当前类可以作为蓝图中的类型使用。新建一个继承UObject的C类CustomObject:UObject默认是无法作为蓝图中的类型使用的,打开关卡蓝图,声明一个CustomObject变量:可以看到,这里无法声明CustomObject类型的变量,我们为CustomObject添加BlueprintType标记宏:这样我们…

我的2022,为什么要跳出舒适圈?

1前言今天的冬日暖阳高照&#xff0c;给我羽绒服下的肉身火一般的燥热&#xff0c;给了我一个错觉&#xff0c;以为到了阳春三月。刚刚送完老妈还有老婆孩子回老家&#xff0c;我坐到电脑机器前&#xff0c;准备捋一下思绪&#xff0c;回首2022的生活和工作。 2 2022 回顾今年用…

从零开始搭建Dubbo环境并整合Dubbo+SpringBoot

Windows环境搭建 1. 安装Zookeeper 下载 zookeeper3.5 下载地址 https://zookeeper.apache.org/releases.html#download 下载完成以后, 解压到一个目录下 然后把 zoo_sample.cfg 复制一份, 重命名为 zoo.cfg 修改配置文件 zoo.cfg 中的 dataDir 这个配置 修改为 dataDir../z…

pygame - 图片移动优化 - 引入面向对象思想

目录 一、基本框架 二、代码段 1、附注释 2、无注释 三、效果展示 备注&#xff1a;pygame - 图片移动优化中未对属性和方法进行封装&#xff0c;本篇文章将引入面向对象思想 一、基本框架 import sys import time import pygamepygame.init()SCREEN_WIDTH 680 SCREEN…

基于机器学习预测销售门店的商品销量详细教程

项目概述: 使用时间序列预测来预测来Corporacin Favorita 的数据的商店销售额。 具体来说,构建一个模型来更准确地预测在不同 Favorita 商店销售的数千种商品的单位销售额。您将使用包含日期、商店和商品信息、促销和单位销售的易于理解的训练数据集来练习您的机器学习技能。…