四.消息队列

news2025/1/17 21:45:57

目录

1 .消息队列概述

2.消息队列的特点

3.ftok函数

3 创建消息队列-msgget( )

3.1发送消息-msgsnd( )

3.2 接收消息-msgrcv( )

4 消息队列的控制


1 .消息队列概述

       消息队列是一种进程间通信的机制,允许不同进程在系统中传递数据。它们通常由内核维护,并提供了一种异步的通信方式,允许进程通过在队列中发送和接收消息进行通信。

消息队列是消息的链表,存放在内存中,由内核维护

2.消息队列的特点

1、消息队列中的消息是有类型的。

2、消息队列中的消息是有格式的。

3、消息队列可以实现消息的随机查询。消息不一定要以先进先出的次序读取,编程时可以按消息的类型读取。

4、消息队列允许一个或多个进程向它写入或者读取消息。

5、与无名管道、命名管道一样,从消息队列中读出消息,消息队列中对应的数据都会被删除。 6、每个消息队列都有消息队列标识符,消息队列的标识符在整个系统中是唯一的。

7、只有内核重启或人工删除消息队列时,该消息队列才会被删除。若不人工删除消息队列,消息队列会一直存在 于系统中。

在 ubuntu 12.04 中消息队列限制值如下:

每个消息内容最多为 8K 字节。

每个消息队列容量最多为 16K 字节 系统中消息队列个数最多为 1609 个。

系统中消息个数最多为 16384 个。

System V 提供的 IPC 通信机制需要一个 key 值,通过 key 值就可在系统内获得一个唯一的消息队列标识符。 key 值可以是人为指定的,也可以通过 ftok 函数获得。

3.ftok函数

ftok函数

ftok()函数是在 Linux/Unix 操作系统中用于创建一个唯一的 key 的函数。

消息队列、信号量等进程间通信方式都需要一个唯一的标识符来标识自己。`ftok()` 函数可以将一个普通文件的路径名和一个整数 ID 转换为一个 key(即 IPC 标识符),返回值为一个 long 类型的 key 值。

ftok()的函数原型为:

#include <sys/types.h> 

#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);

 功能:通过文件名和目标值共同创造一个键值并返回值。获得项目相关的唯一的 IPC 键值。

参数:

 pathname:任意一个文件名(文件名或者目录名)路径名

 proj_id:目标值,范围一般是0~127,项目 ID,非 0 整数(只有低 8 位有效)。

返回值: 成功:返回 key 的键值。 失败:‐1

 如果使用ftok函数获取键值,得到的键值是由ftok的第一个 参数对应文件的信息和第二个参数一起决定的。

其中,参数 `pathname` 是指文件的路径名,`proj_id` 是一个用户自定义的整数 ID。

`ftok()` 函数会根据给定的文件路径名和整数 ID 生成一个唯一的 key。在多个进程中使用同一个 key 可以让它们访问同一个 IPC 对象,例如同一个消息队列或同一个信号量集合。

需要注意的是,如果文件不存在或者无法访问,或者多个进程使用不同的文件路径名和/或整数 ID 调用 `ftok()` 生成相同的 key,则可能导致 IPC 系统中的冲突。因此,在使用 `ftok()` 函数时需要选择一个合适的文件路径名和整数 ID,并确保所有进程都使用相同的参数来调用该函数。

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

int main(int argc, char const *argv[])
{
    //使用ftok函数获取键值
    //只要保证ftok的第一个参数对应的文件和第二个参数值相同,则不管程序运行多少遍或者多少个进程或者键值
    //键值一定都是唯一的
    key_t mykey;
    if((mykey = ftok(".", 100)) == -1)
    {
        perror("fail to ftok");
        exit(1);
    }

    printf("key = %#x\n", mykey);

    
    return 0;
}

3 创建消息队列-msgget( )

man msgget

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

       int msgget(key_t key, int msgflg);

功能:创建一个消息队列,并得到该消息队列的id

 参数:

 key:键值,唯一的键值确定唯一的消息队列

 方法1:任意指定一个数

方法2:使用ftok函数获取键值

 msgflg:消息队列的访问权限

 一般设置为 IPC_CREAT | IPC_EXCL | 0777 或者 IPC_CREAT | 0777。

 返回值:

 成功:消息队列的id  失败:‐1

使用shell命令操作消息队列:

查看消息队列 : ipcs ‐q  

删除消息队列 : ipcrm ‐q msqid 

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

int main(int argc, char const *argv[])
{
    //通过ftok函数获取ipc键值
    key_t mykey;
    if((mykey = ftok(".", 100)) == -1)
    {
        perror("fail to ftok");
        exit(1);
    }

    printf("mykey = %#x\n", mykey);

    //通过msgget函数创建一个消息队列
    int msqid;
    if((msqid = msgget(mykey, IPC_CREAT | 0666)) == -1)
    {
        perror("fail to msgget");
        exit(1);
    }

    printf("msqid = %d\n", msqid);

    system("ipcs -q");

    return 0;
}

3.1发送消息-msgsnd( )

man 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:消息队列的id

 msgp:要写入的数据,需要自己定义结构体

struct struct_name{

 long mtype; //消息的编号,必须大于0

 char mtext[128]; //消息正文,可以定义多个成员

 }

msgsz:消息正文的大小,不包括消息的编号长度

msgflg:标志位

 0 阻塞

 IPC_NOWAIT 非阻塞

返回值:

 成功:0

失败:‐1

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

#define N 128

typedef struct{
    long msg_type; //消息类型,必须在结构体的第一个位置并且类型必须是long
    char msg_text[N]; //消息正文,也可以有多个成员并且类型也可以是任意
}MSG;

#define MSGTEXT_SIZE (sizeof(MSG) - sizeof(long))//此处表示消息正文的大小

int main(int argc, char const *argv[])
{
    //使用ftok函数获取键值
    key_t key;
    if((key = ftok(".", 100)) == -1)
    {
        perror("fail to ftok");
        exit(1);
    }

    //使用msgget函数创建一个消息队列
    int msgid;
    if((msgid = msgget(key, IPC_CREAT | 0777)) == -1)
    {
        perror("fail to msgget");
        exit(1);
    }

    system("ipcs -q");

    //使用msgsnd函数向消息队列中发送数据(写操作)
    MSG msg1 = {1, "hello world"};
    MSG msg2 = {2, "nihao beijing"};
    MSG msg3 = {2, "hello kitty"};
    MSG msg4 = {3, "welcome to china"};
    
    if(msgsnd(msgid, &msg1, MSGTEXT_SIZE, 0) == -1)
    {
        perror("fail to msgsnd");
        exit(1);
    }

    if(msgsnd(msgid, &msg2, MSGTEXT_SIZE, 0) == -1)
    {
        perror("fail to msgsnd");
        exit(1);
    }

    if(msgsnd(msgid, &msg3, MSGTEXT_SIZE, 0) == -1)
    {
        perror("fail to msgsnd");
        exit(1);
    }

    if(msgsnd(msgid, &msg4, MSGTEXT_SIZE, 0) == -1)
    {
        perror("fail to msgsnd");
        exit(1);
    }

    system("ipcs -q");


    return 0;
}

3.2 接收消息-msgrcv( )

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

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, 5 long msgtyp, int msgflg);

 功能:从消息队列中接收数据(读操作),接收的数据会从消息队列中删除

 参数:

 msqid:消息队列id

 msgp:保存接收到的数据的结构体

 struct struct_name{

 long mtype; //消息的编号,必须大于0

 char mtext[128]; //消息正文,可以定义多个成员

 }

msgsz:消息正文的大小

 msgtyp:设置要接收哪个消息

 msgtyp = 0 按照写入消息队列的顺序依次读取

 msgtyp > 0 只读取消息队列中消息编号为当前参数的第一个消息

msgtyp < 0 只读取消息队列中小于等于当前参数的绝对中内最小的第一个消息

 msgflg:标志位

 0 阻塞

 IPC_NOWAIT 非阻塞

 返回值:

 成功:接收到的消息正文的长度

 失败:‐1

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

#define N 128

typedef struct{
    long msg_type;
    char msg_text[N];
}MSG;

#define MSGTEXT_SIZE (sizeof(MSG) - sizeof(long))

int main(int argc, char const *argv[])
{
    //使用ftok函数获取键值
    key_t key;
    if((key = ftok(".", 100)) == -1)
    {
        perror("fail to ftok");
        exit(1);
    }

    //使用msgget函数创建一个消息队列
    int msgid;
    if((msgid = msgget(key, IPC_CREAT | 0777)) == -1)
    {
        perror("fail to msgget");
        exit(1);
    }

    system("ipcs -q");

    //通过msgrcv函数接收消息队列中的信息(读操作)
    //注意:如果没有第四个参数指定的消息时,msgrcv函数会阻塞等待
    MSG msg;

    //如果第四个参数为0,则按照先进先出的方式读取数据
    //if(msgrcv(msgid, &msg, MSGTEXT_SIZE, 0, 0) == -1) 
    //如果第四个参数为>0,则获取当前值得消息类型的数据
    //if(msgrcv(msgid, &msg, MSGTEXT_SIZE, 2, 0) == -1)
    //如果第四个参数为<0,则获取当前值得绝对值内消息类型最小的数据
    if(msgrcv(msgid, &msg, MSGTEXT_SIZE, -3, 0) == -1)
    {
        perror("fail to msgrcv");
        exit(1);
    }

    printf("recv_msg = %s\n", msg.msg_text);

    system("ipcs -q");
    
    return 0;
}

4 消息队列的控制

man msgctl

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

       int msgctl(int msqid, int cmd, struct msqid_ds *buf);

功能:设置或者获取消息队列的信息

 参数:

msqid:指定的消息队列的id

 cmd:具体操作的指令

 IPC_SET :设置属性

 IPC_STAT: 获取属性

 IPC_RMID: 删除消息队列

msqid_ds:设置或者获取消息队列的属性

 返回值:

 成功:0  失败:‐1

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

int main(int argc, char const *argv[])
{
    //使用ftok函数获取键值
    key_t key;
    if((key = ftok(".", 100)) == -1)
    {
        perror("fail to ftok");
        exit(1);
    }

    //使用msgget函数创建一个消息队列
    int msgid;
    if((msgid = msgget(key, IPC_CREAT | 0777)) == -1)
    {
        perror("fail to msgget");
        exit(1);
    }

    printf("msgid = %d\n", msgid);
    system("ipcs -q");

    //通过msgctl函数删除消息队列
    if(msgctl(msgid, IPC_RMID, NULL) == -1)
    {
        perror("fail to msgctl");
        exit(1);
    }

    system("ipcs -q");
    
    return 0;
}

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

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

相关文章

c语言-指针练习题

目录 前言一、题目一二、题目二总结 前言 为了巩固c语言中关于指针知识点的掌握&#xff0c;本篇文章记录关于指针的练习题。 一、题目一 有n个整数&#xff0c;使前面各数顺序往后移动m个位置&#xff0c;最后m个数变成最前面的m个数 写一函数实现以上功能&#xff0c;在主函…

【Vue2+3入门到实战】(5)Vue基础之Computed计算属性 详细示例

目录 一、今日学习目标1.computed计算属性 二、computed计算属性1.概念2.语法3.注意4.案例5.代码准备 三、computed计算属性 VS methods方法1.computed计算属性2.methods计算属性3.计算属性的优势4.总结 四、计算属性的完整写法五、综合案例-成绩案例六、Computed计算属性总结 …

荣耀之城(富饶之地)

规则简介 这是一个回合制的游戏&#xff0c;每个回合都是先选角色然后按照角色编号依次执行回合。 8个角色&#xff1a;刺客、小偷、魔术师、国王、住持、商人、建筑师、领主 根据人数的不同&#xff0c;按照不同的规则依次选取一个角色&#xff0c;国王第一个选&#xff0c…

【数学建模美赛M奖速成系列】Matplotlib绘图技巧(二)

Matplotlib绘图技巧&#xff08;二&#xff09; 写在前面2. 函数间区域填充函数fill_between()和fill()参数&#xff1a; 3. 散点图 scatter4. 直方图 hist5. 条形图 bar5.1 一个数据样本的条形图参数&#xff1a; 5.2 多个数据样本进行对比的直方图5.3 水平条形图参数 5.4 绘制…

Redis内存使用率高,内存不足问题排查和解决

问题现象 表面现象是系统登录突然失效&#xff0c;排查原因发现&#xff0c;使用redis查询用户信息异常&#xff0c;从而定位到redis问题 if (PassWord.equals(dbPassWord)) {map.put("rtn", 1);map.put("value", validUser);session.setAttribute("…

结构体:子网掩码

#include<iostream> using namespace std; union IP //创建共用体 {unsigned char a[4];unsigned int ip; }; IP getIP() //获取ip函数 {int a, b, c, d;scanf_s("%d.%d.%d.%d", &a, &b, &c, &d);IP address;address.a[3] a; address.a[2] …

C. Load Balancing 一个序列同时加一个数和减一个数,直到最大和最小之间相差最大为1(结论可记住)

题目&#xff1a; https://atcoder.jp/contests/abc313/tasks/abc313_c 思想&#xff1a;1.给定一个固定的B&#xff0c;求使A等于B所需的最小运算次数 2.在所有最大值和最小值最多相差1的B中&#xff0c;找出一个所需的运算次数最少的&#xff0c;即1 做法&#xff1a;构造…

Vue项目优化-组件配置化、插件使用

Vue中可以根据需要去加载插件&#xff0c;一些自己写的插件在多个项目中都是需要用到的&#xff0c;通过把它们插件化&#xff0c;可以实现在需要用到的项目中便捷地复用&#xff0c;实现热拔插。 一、问题背景 以弹窗表单组件为例&#xff0c;平常我们使用弹窗组件都是通过页面…

C单片机数据类型与格式化

C语言数据类型 关键字位数表示范围stdint关键字ST关键字举例unsigned char80 ~ 255uint8_tu8u8 data 128char8-128 ~ 127int8_ts8s8 temperature 25unsigned short160 ~ 65535uint16_tu16u16 counter 5000short16-32768 ~ 32767int16_ts16s16 position 32767unsigned int3…

[Angular] 笔记 21:@ViewChild

chatgpt: 在 Angular 中&#xff0c;ViewChild 是一个装饰器&#xff0c;用于在组件类中获取对模板中子元素、指令或组件的引用。它允许你在组件类中访问模板中的特定元素&#xff0c;以便可以直接操作或与其交互。 例如&#xff0c;如果你在模板中有一个子组件或一个具有本地…

Autosar MCAL-RH850P1HC Dio配置

文章目录 DioDioGeneralDioCriticalSectionProtectionDioDevErrorDetectDioDeviceNameDioFlipChannelApiDioMaskedWritePortApiDioUseWriteVerifyErrorInterfaceDioVersionCheckExternalModulesDioVersionInfoApiDioWriteVerifyDioWriteVerifyErrorInterface DioPortP0-P9DioPo…

关于mysql8.0相关的升级

不知不觉&#xff0c;MySQL8.0已经有好多个GA小版本了。目前互联网上也有很多关于MySQL8.0的内容了&#xff0c;MySQL8.0版本基本已到稳定期&#xff0c;相信很多小伙伴已经在接触8.0了。本篇文章主要介绍从5.7升级到8.0版本的过程及注意事项&#xff0c;有想做版本升级的小伙伴…

技术探秘:在RISC Zero中验证FHE——RISC Zero应用的DevOps(2)

1. 引言 前序博客&#xff1a; 技术探秘&#xff1a;在RISC Zero中验证FHE——由隐藏到证明&#xff1a;FHE验证的ZK路径&#xff08;1&#xff09; 技术探秘&#xff1a;在RISC Zero中验证FHE——由隐藏到证明&#xff1a;FHE验证的ZK路径&#xff08;1&#xff09; 中&…

DDOS攻击原理,如何解读?

互联网安全现状 随着网络世界的高速发展&#xff0c;各行业数字化转型也在如火如荼的进行。但由于TCP/IP网络底层的安全性缺陷&#xff0c;钓鱼网站、木马程序、DDoS攻击等层出不穷的恶意攻击和高危漏洞正随时入侵企业的网络&#xff0c;如何保障网络安全成为网络建设中的刚性…

【JavaEE】多线程(7) -- 线程池的概念和简单实现

目录 1.线程池是什么 2.标准库中的线程池 2.1ThreadPoolExecutor 2.2构造方法参数介绍 2.3拒绝策略(面试易考) 2.4Executor的使用 3.实现线程池 1.线程池是什么 线程池是一种用来管理线程的机制&#xff0c;它可以有效地控制线程的创建、复用和销毁&#xff0c;从而提高程…

使用flutter开发windows桌面软件读取ACR22U设备的nfc卡片id,5分钟搞定demo

最近有个需求&#xff0c;要使用acr122u读卡器插入电脑usb口&#xff0c;然后读取nfc卡片的id&#xff0c;并和用户账号绑定&#xff0c;调研了很多方式&#xff0c;之前使用rust实现过一次&#xff0c;还有go实现过一次&#xff0c;然后使用electron的时候遇到安装pcsc-lite失…

2024年【危险化学品经营单位安全管理人员】复审考试及危险化学品经营单位安全管理人员模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 危险化学品经营单位安全管理人员复审考试是安全生产模拟考试一点通总题库中生成的一套危险化学品经营单位安全管理人员模拟考试&#xff0c;安全生产模拟考试一点通上危险化学品经营单位安全管理人员作业手机同步练习…

c++ 简单实用万能异常捕获

多层捕获异常&#xff0c;逐渐严格。并打印出错信息和位置&#xff1a;哪个文件&#xff0c;哪个函数&#xff0c;具体哪一行代码。 #include <stdexcept> // 包含标准异常类的头文件try {int a 2 / 0; }catch (const std::runtime_error& e) {// 捕获 std::runt…

【Pytorch】学习记录分享10——PyTorchTextCNN用于文本分类处理

【Pytorch】学习记录分享10——PyTorchTextCNN用于文本分类处理 1. TextCNN用于文本分类2. 代码实现 1. TextCNN用于文本分类 具体流程&#xff1a; 2. 代码实现 # coding: UTF-8 import torch import torch.nn as nn import torch.nn.functional as F import numpy as np…

Spring高手之路-Spring AOP

目录 什么是AOP Spring AOP有如下概念 补充&#xff1a; AOP是如何实现的 Spring AOP 是通过代理模式实现的。 Spring AOP默认使用标准的JDK动态代理进行AOP代理。 什么是AOP AOP(Aspect-Oriented Programming)&#xff0c;即面向切面编程&#xff0c;用人话说就是把公共的…