Linux高级编程_31_消息队列

news2024/12/23 0:25:04

文章目录

  • 消息队列
    • 作用:
    • 特点:
    • 消息队列限制值:
    • 注意:
    • 命令:
    • ftok函数
      • 作用:
      • 语法:
    • msgget函数
      • 作用:
      • 语法:
    • msgsnd函数
      • 作用:
      • 语法:
    • msgrcv函数
      • 作用:
      • 语法:
    • 基于消息队列的聊天程序

消息队列

作用:

进程间通信

特点:

  • 1 消息队列中的消息是由类型的

    • 类型: 自定义的结构体,第一个成员必须是long型的表示为该消息的类型:

      • 如:

         typedef struct 结构体名称
         {
             long type;   // 类型必须是 long  但是名字随意
             
             //消息的正文
             char name[50];
             int age;
             ....
         }别名;
        
  • 2 消息队列中的消息 是有格式的

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

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

  • 5 与无名管道、命名管道一样,从消息队列中读出消息,消息队列中对应的数据都会被删除

  • 6 每个消息队列都有消息队列标识符, 消息队列的标识符在整个系统中都是唯一的

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

消息队列限制值:

  • 每个消息内容最多为 8K 字节 差不多2000多个汉字吧
  • 每个消息队列容量最多为 16K 字节
  • 系统中消息队列个数最多为 1609 个
  • 系统中消息个数最多为 16384 个

注意:

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

命令:

- ipcs -q
- ipcrm -q 要删除的消息队列id

ftok函数

作用:

获取项目相关的唯一的 IPC 键值

语法:

头文件: <sys/types.h>
    	<sys/ipc.h>
    
key_t ftok(const char* pathname,int proj_jd)
    参数:
    	pathname:文件地址,保证是存在的路径就行。
    	proj_jd : 项目id  随便给
    返回值:
    	计算得到的key值

msgget函数

作用:

获取消息队列

语法:

头文件:   #include <sys/msg.h>
函数:		int msgget(key_t key,int msgflg);
功能:
    	创建一个新的或打开一个已经存在的消息队列,不同的进程调用此函数,只要用相同 key 值就能获得同一个消息队列的标识符

参数:
    key: IPC 键值;
    msgflg: 标识函数的行为及消息队列的权限。
        	msgflg 的取值:
        				IPC_CREAT: 创建消息队列
                          IPC_EXCL: 检测消息队列是否存在
    位或权限位:消息队列位或权限位后可以设置消息队列的访问权限,格式和open函数的mode_t一样,但可执行权限未使用。
     
           如:
IPC_CREAT | 0666
如果消息队列不存在,则创建该消息队列,所有用户可读可写
如果消息队列以存在,则使用已经存在的消息队列
                            
     返回值:
         成功:     创建的消息队列的id,
		失败:     返回 -1

示例:消息队列的创建

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
int main(int argc, char const *argv[])
{
    // 1.获取key
    key_t key = ftok("/", 2402);
    // 2.创建消息队列
    int msgid = msgget(key, IPC_CREAT | 0666);
    //  打印key键值
    printf("key = %d\n", key);
    //  打印消息队列id
    printf("msgid = %d\n", msgid);
    return 0;
}

使用 ipcs -q 查看

在这里插入图片描述

msgsnd函数

作用:

发送消息

语法:

int msgsnd()
    参数:
    	1  msqid:消息队列id
        2   msgp:发送的消息的结构体指针
        3   msgsz:发送消息的正文大小
            		如何计算: sizeof(struct) - sizeof(long)  结果就是正文大小
        4  msgflg:标记
             0:msgsnd 调用阻塞直到条件满足为止。
			IPC_NOWAIT: 若消息没有立即发送则调用该函数的进程会立即返回。
        返回值:
			成功0, 失败-1
0阻塞   1解阻塞			

msgrcv函数

作用:

接收消息

语法:

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
参数:
    	msqid:消息队列id
		msgp:接收消息的结构体指针变量
		msgsz:接收的消息的正文大小
		msgtyp:接收的消息的类型
		msgflg:标记
			0:msgsnd 调用阻塞直到条件满足为止。
			IPC_NOWAIT:若消息没有立即发送则调用该函数的进程会立即返回。

基于消息队列的聊天程序

思路:

  • 1 请输入昵称
  • 2 请输入接收的消息类型
  • 3 创建消息队列 【得同一个key】
  • 4 创建两个子进程 一个发 一个收
  • 5 当前进程回收子进程

代码:

#include <stdio.h>
#include <sys/msg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h> 
#include <wait.h>
typedef struct msg
{
    // 类型
    long type;
    // 谁发的
    char name[50];
    // 消息内容
    char info[300];
    // 时间
    char xxz_time[50];
} MSG;
char *getTimer()
{
    time_t tim;
    time(&tim);
    struct tm *t = localtime(&tim);
    // 开辟内存来存储时间
    char *tstr = (char *)calloc(50, sizeof(char));
    // 组包
    sprintf(tstr, "%d年%02d月%02d日 %02d:%02d:%02d\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
    printf("%s", tstr);
    return tstr;
}

int main(int argc, char const *argv[])
{
    // 存储姓名
    char name[50] = {0};
    printf("你的昵称\n");
    fgets(name, 50, stdin);

    // 接收消息类型
    printf("你的消息类型是:\n");
    long type = 0;
    scanf("%ld", &type);

    // 获取键值
    int key = ftok("/", 951357);
    // 获取消息队列
    int msgid = msgget(key, IPC_CREAT | 0666);
    // 创建两进程来实现 收发消息
    int i = 0;
    for (i = 0; i < 2; i++)
    {
        int xxz_pid = fork();
        if (xxz_pid == 0)
        {
            break;
        }
    }
    // 子进程1   发
    if (i == 0)
    {
        while (1)
        {
            MSG m1;
            strcpy(m1.name, name); 
            printf("他的信息类型:\n");
            scanf("%ld", &(m1.type));
            printf("请输入要说的话:\n");
            scanf("%s", m1.info);
            char *t = getTimer();
            strcpy(m1.xxz_time, t);
            free(t);
            // 消息队列进行发消息   0 阻塞
            msgsnd(msgid, &m1, sizeof(MSG) - sizeof(long), 0);
            //  结束条件  当两个字符串内容一致的时候退出
            if (strcmp(m1.info, "88") == 0)
            {
                break;
            }
        }
    }
    // 子进程2 收
    else if (i == 1)
    {
        while (1)
        {
            MSG m1;
            // 消息队列 接收消息
            msgrcv(msgid, &m1, sizeof(MSG) - sizeof(long), type, 0);
            // printf("%s\t%s说:%s\n", m1.xxz_time, m1.name, m1.info);
            if (strcmp(m1.info, "88") == 0)
            {
                break;
            }
        }
    }
    else
    { // 进程回收
        while (waitpid(-1, NULL, WNOHANG) != -1);
        // 消息队列删除
        msgctl(msgid, IPC_RMID, NULL);
    }
    return 0;
}

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

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

相关文章

QT实现QInputDialog中文按钮

这是我记录Qt学习过程心得文章的第三篇&#xff0c;主要是为了方便QInputDialog输入框的使用&#xff0c;通过自定义的方式&#xff0c;按钮中文化&#xff0c;统一封装成一个函数&#xff0c;还是写在了Skysonya类里面。 实现代码&#xff1a; //中文按钮文本输入对话框 QSt…

【gRPC】1—gRPC是什么

gRPC是什么 ⭐⭐⭐⭐⭐⭐ Github主页&#x1f449;https://github.com/A-BigTree 笔记链接&#x1f449;https://github.com/A-BigTree/Code_Learning ⭐⭐⭐⭐⭐⭐ 如果可以&#xff0c;麻烦各位看官顺手点个star~&#x1f60a; &#x1f4d6;RPC专栏&#xff1a;https://b…

鸿蒙--播放器状态控制

各个页面共享同一个播放状态&#xff0c;而且可以互相控制&#xff0c;如果传递来传递去会非常的麻烦&#xff0c;但是他们都是Tabs组件内的&#xff0c;我们在index页面提供一个状态&#xff0c;在各个组件接收即可 创建两个子组件&#xff0c;一个是播放控制的子组件&#xf…

1. Oracle 安装报错——环境变量过长

文章目录 1. 报错详细信息2. 解决方案2.1 方案一&#xff1a;修改配置文件cvu_prereq.xml2.2 方案二&#xff1a;修改环境变量配置 1. 报错详细信息 安装 Oracle 过程中&#xff0c;在执行 “先决条件检查” 时报错&#xff1a; 报错内容&#xff1a; This test checks wheth…

【自然语言处理】(3) --RNN循环神经网络

文章目录 RNN循环神经网络一、传统神经网络的问题二、RNN的基本结构三、计算过程4. RNN的局限 总结 RNN循环神经网络 循环神经网络&#xff08;RNN&#xff0c;Recurrent Neural Network&#xff09;是一种用于处理序列数据的神经网络模型。其关键特性在于网络节点&#xff08…

现代数字信号处理I-P2概率论学习笔记

目录 学习视频链接&#xff1a; 1. 三要素及关系 2. 期望和方差的定义及基本性质 2.1 期望&#xff08;均值&#xff09;定义&#xff1a; 在实际工作中很难获得随机变量的分布或者概率密度&#xff0c;用矩描述随机变量 2.2 期望基本性质&#xff1a; 2.3 方差定义 2.…

Android Studio Koala Feature Drop 稳定版现已推出

作者 / Android Studio 产品经理 Sandhya Mohan Android Studio Koala Feature Drop (2024.1.2) 现已推出&#xff01;&#x1f428; &#x1f517; Android Studio https://developer.android.google.cn/studio 今年早些时候&#xff0c;我们宣布每个 Android Studio 动物版本…

10月9日笔记(域内用户登录凭据窃取)

缺&#xff1a;BloodHound自动化分析域环境未实现&#xff08;环境问题&#xff09; 获取常见应用软件凭据 为了扩大可访问的范围&#xff0c;测试人员通常会搜索各种常见的密码存储位置&#xff0c;以获取用户凭据。一些特定的应用程序可以存储密码&#xff0c;以方便用户管…

python的特殊方法——魔术方法

前言 __init__(self[]) ​编辑 __call__(self [, ...]) __getitem__(self, key) __len__(self) __repr__(self) / __str__(self) __add__(self, other) __radd__(self, other) 参考文献 前言 官方定义好的&#xff0c;以两个下划线开头且以两个下划线结尾来命名的方法…

PostgreSQL学习笔记四:GUI管理工具

PostgreSQL 是一款广泛使用的开源关系数据库管理系统&#xff0c;拥有许多图形用户界面&#xff08;GUI&#xff09;工具来帮助用户更高效地管理数据库。以下是一些流行的 PostgreSQL 管理工具&#xff1a; pgAdmin&#xff1a; 一个流行的开源 PostgreSQL GUI 工具&#xff0c…

处理“navicat premium 2003 - 无法在 192.168.10.140 上连接到 MySQL 服务器(10060“未知错误“)”的问题:

以下是一些可能的解决方法来处理“navicat premium 2003 - 无法在 192.168.10.140 上连接到 MySQL 服务器&#xff08;10060"未知错误"&#xff09;”的问题&#xff1a; **一、检查 MySQL 服务状态** 1. 确认 MySQL 服务是否正在运行。你可以在服务器上通过任务管…

Django makemigrations时出现TypeError: ‘module‘ object is not iterable

使用Python 3.11、Django 5.1.2 写完model进行makemigrations时出现报错 报错的最下面提到了我自己创建的一个应用里的urls.py&#xff0c;尝试着给里面加上一个列表 然后问题解决了。。。 不知道为什么 makemigrations的时候会去检查urls。。。

mybatisPlus对于pgSQL中UUID和UUID[]类型的交互

在PGSQL中&#xff0c;有的类型是UUID和UUID[]这种类型&#xff0c;在mybatis和这些类型交互的时候需要手动设置类型处理器才可以&#xff0c;这里记录一下类型处理器的设置 /*** UUID类型处理器*/ public class UUIDTypeHandler extends BaseTypeHandler<UUID> {/*** 获…

Kubernetes中的pod管理及优化

华子目录 什么是pod1.创建自主式pod&#xff08;生产不推荐&#xff09;优点缺点示例1示例2示例3示例4 2.利用控制器管理pod&#xff08;推荐&#xff09;应用版本的更新 3.利用yaml文件部署应用优点3.1yaml配置文件参数3.2如何获取资源帮助 yaml文件编写示例1.运行简单的单个容…

实现std::sort,replace,fill,accumulate,equal等函数

std::sort /// <summary>/// std::sort 是从小到大排列的/// </summary>/// <typeparam name"IteratorClass"></typeparam>/// <typeparam name"ComparingFunctions"></typeparam>/// <param name"itBegin&qu…

PAT甲级-1150 Travelling Salesman Problem

题目 题目大意 旅行商问题是NP-hard问题&#xff0c;即没有多项式时间内的解法&#xff0c;但是可以验证答案是否正确。给定一个无向图&#xff0c;判断简单环&#xff0c;复杂环和非环。对应“TS simple cycle”、“TS cycle”、“Not a TS cycle”。还要求出环的最小路径权值…

力扣11-盛最多水的容器

题目 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xff1a;你不能倾斜容器。…

DAY28||39.组合总数 |40.组合总和Ⅱ |131.分割回文串

39.组合总数 题目&#xff1a;39. 组合总和 - 力扣&#xff08;LeetCode&#xff09; 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以…

Java基本数据类型转换

一、自动类型转换 1.基本介绍 当Java程序在进行赋值或者运算时&#xff0c;精度小的类型自动转换为精度大的数据类型&#xff0c;这个就是自动类型转换数据类型按精度&#xff08;容量&#xff09;大小进行排序为&#xff1a; ![在这里插入图片描述](https://i-blog.csdnimg.…

数据中心物理安全的历史和演变

在当今的数字时代&#xff0c;数据中心托管已成为我们互联世界的支柱。这些设施在存储、管理和处理我们日常生活所需的大量信息方面发挥着至关重要的作用。从社交媒体平台和电子商务网站到流媒体服务和云计算&#xff0c;数据中心为我们依赖的数字服务提供支持。 随着企业越来…