【Linux】管道通信和 system V 通信

文章目录

  • 一、进程通信原理(让不同进程看到同一份资源)
  • 二、管道通信
    • 2.1 管道原理及其特点
    • 2.1 匿名管道和命名管道
  • 三、共享内存通信
    • 3.1 共享内存原理
    • 3.2 创建和关联共享内存
    • 3.3 去关联、ipc 指令和删除共享内存
  • 四、消息队列和信号量(了解)
    • 4.1 消息队列
    • 4.2 信号量
    • 4.3 system V

一、进程通信原理(让不同进程看到同一份资源)

  尽管每个进程在其独立的地址空间中运行,它们之间并没有直接共享的内存区域,但所有进程都共享同一个OS操作系统。这个共享的操作系统会提供相应的进程通信机制,如共享内存、消息传递、信号、管道、套接字等。这些机制允许进程间实现数据的转发和共享,即便它们在内存中没有直接共享的空间。
  因此,进程通信(Inter-Process Communication, IPC)的原理就是:操作系统是所有进程共享的第三方实体,为进程提供了一套丰富的通信工具和协议,使得进程能够在保持独立性的同时,又让不同的进程看到同一份资源!!!以此实现数据的共享和任务的协调。这种设计不仅提高了系统的稳定性和效率,还确保了通信的安全性和有效性,能够管理了进程间的同步和互斥,防止数据在传输过程中发生冲突。

二、管道通信

2.1 管道原理及其特点

  我们把从一个进程连接到另一个进程的一个数据流称为一个 管道,这个数据流就是一段内核缓冲区,默认大小为 4kb,会根据实际情况做适当的调整。也可以叫做伪文件,不会刷新到磁盘。管道的操作形式是基于文件的,它只允许单向通信,如果要双向通信的话,需要建立两个管道,“互相读写”!

管道通信时可能会遇到以下四种情况:

  • 1、读写端正常,管道如果为空,读端就要阻塞
  • 2、读写端正常,管道如果被写满,写端就要阻塞
  • 3、读端正常读,写端关闭,读端就会读到0,表明读到了文件(pipe)结尾,不会被阻塞
  • 4、写端正常写,读端关闭了。操作系统就要向目标文件发送 SIGPIPE(13) 信号,杀掉正在写入的进程


管道通信特点:

  • 1、管道是基于文件的,且文件生命周期是跟随进程的
  • 2、为了保护管道文件的数据安全,进程之间需要进行进程协同,同步与互斥
  • 3、匿名管道,仅允许有血缘关系的进程(常用于父子)进行通信,且是单向通信的
  • 4、是面向字节流的(面向字节流读取, 跟写的时候的格式无关, 读取的时候只跟字节数有关)

2.1 匿名管道和命名管道

匿名管道:int pipe(int pipefd[2]);
  pipefd 数组是一个输入输出型参数,创建成功返回 0,创建失败返回 -1,并设置错误码!pipefd[0] 表示读端文件描述符,pipedf[1] 表示写端文件描述符。匿名管道,只允许有血缘关系的进程之间进行进程间通信,管道是单向通信的,在我们 fork 之后,应让父子进程中的一方写入,另外一方读取。

命名管道:int mkfifo(const char *pathname, mode_t mode);
  创建成功返回 0,失败返回 -1,并设置错误码,参数 pathname 为文件名, mode 是其对应的权限 。命名管道是一种进程间通信机制,它和匿名管道的区别是,它可以让没有血缘关系的进程进行通信。同时命名管道有对应的 inode ,可以理解为磁盘上的伪文件。但它不是一个实际的数据存储文件,无论写入多少数据,其大小都是 0
  命名管道通过路径+文件名作为该文件的唯一标识,用法和普通文件一样,使用 open、write、read 接口,但仍得保持其单向通信的特性,一端读取,一段写入。且需要等待写端打开之后,读端才会打开文件,否则读端会阻塞等待。

三、共享内存通信

3.1 共享内存原理

  共享内存(Shared Memory)是进程间通信的一种方式,它允许两个或多个进程访问同一块物理内存区域。每个进程都有自己的虚拟地址空间,共享区存在于地址空间上的栈区和堆区之间。在用户需要申请共享内存时,操作系统在物理内存中申请一块空间,每个进程在自己的共享区中与这块物理内存单独建立页表映射,这种多个进程共同映射同一块物理内存的操作就叫做共享内存(即让不同的进程,看到同一份资源)
  这些进程可以通过共享区页表映射直接读写这块物理内存,如同访问本进程的私有内存一样,进行数据交互。因此,它是内存级别的通信,没有额外的复制开销,使得通信速度非常快。但由于有多个进程访问同一块空间,也得考虑同步和互斥控制,我们可以通过使用管道、条件变量、消息队列、信号量,加锁等方法来避免竞态条件和数据不一致的问题。

3.2 创建和关联共享内存

从不同角度上来理解实现共享内存的步骤:
操作系统角度:
①创建共享内存
②删除共享内存
进程角度:
③关联共享内存
④去关联共享内存
因此我们需要按①③④②顺序区管理一个共享内存

创建共享内存 int shmget(key_t key, size_t size, int shmflg);
  创建成功返回 shmid,失败返回 -1 ,错误码被设置。size 为要申请的共享内存大小,由于操作系统对内存管理的最小单位是页(4KB),所以 size 建议设置成为页的整数倍。

shmflg为创建共享内存的选项,常见的有两个选项:

  • IPC_CREAT:创建共享内存,不存在,就创建,存在,就获取
  • IPC_EXCL:不单独使用,必须和IPC_CREAT配合使用。如果不存在指定的共享内存,就创建。存在,则出错返回。这样可以保证,如果shmget函数调用成功,一定是一个全新的共享内存。
  • 并且 shmflg 可以按位或文件权限,设置共享内存权限,类似shmget(key,SIZE,flags | 0666);

现在关键的问题来了,你怎么保证不同的进程看到的是同一个共享内存呢?
  操作系统中可能有很多个共享内存在被使用,所以我们就需要用一个唯一值来标识每一个共享内存,即 key 值。在内核中,让不同的进程看到同一份共享内存,让他们拥有同一个 key 即可。

那么这个 key 由谁来提供呢?
  如果由操作系统来提供,那么创建共享内存的进程可以知道 key 值,但是其它要使用这个共享内存的进程如何获取这个 key 呢,不可能让创建共享内存的进程通信给他们吧。因为此时你要解决的就是双方通信的问题,这就变成了鸡生蛋、蛋生鸡的问题。所以 key 值必须由用户之间指定、用户之间的约定的,这样才能确保看到的是同一个共享内存。

获取 key 值:key_t ftok(const char *pathname, int proj_id);
  将文件路径和一个项目标识符,通过一套算法转化为唯一 key 值,这里的路径名和项目标识符就是用户之间约定好的,成功返回一个唯一的 key 值,失败返回 -1,错误码被设置。

  创建共享内存成功返回共享内存标识符 shmid ,它是一个由系统分配的唯一的整数值,用于唯一标识一个共享内存段。key 在操作系统内标定唯一性,而shmid 只在你的进程内,用来表示资源的唯一性!!!接下来的对共享内存的操作(关联、去关联、删除)我们都采用 shmid 作为参数而非 key

关联共享内存:void *shmat(int shmid, const void *shmaddr, int shmflg);

参数:

  • shmid:共享内存标识符,由 shmget 函数返回
  • shmaddr:指定附加共享内存的位置。如果设置为 NULL,则由系统选择地址
  • shmflg:控制共享内存的访问方式和其他选项的标志,一般设置为0使用默认行为

  成功返回附加到进程地址空间的共享区的地址。失败,返回 (void *) -1,错误码被设置。使用类似于 molloc,使用时需要强转为需要的指针类型。对此我们就像访问自己的私有内存一样,与其它进程进行数据交互通信

3.3 去关联、ipc 指令和删除共享内存

去关联共享内存:int shmdt(const void *shmaddr);
  成功返回0,失败返回-1,错误码被设置。参数为共享区中 shmat 函数返回的共享区起始地址

ipc 系列相关指令:
一、查看IPC

  • ipcs 和 ipcs -a : 查看所有IPC对象
  • ipcs -q: 查看消息对列对象
  • ipcs -m: 查看共享内存对象
  • ipcs -s: 查看信号量对象

二 、删除 IPC 对象

  • ipcrm -Q key :根据键值key,删除指定的消息对列
  • ipcrm -q id:根据ID,删除指定的消息对列
  • ipcrm -M key:根据键值key,删除指定的共享内存
  • ipcrm -m id:根据ID,删除指定的共享内存
  • ipcrm -S key :根据键值key,删除指定的信号量
  • ipcrm -s id:根据ID,删除指定的信号量

删除共享内存:int shmctl(int shmid, int cmd, struct shmid_ds *buf);

参数:

  • shmid:由 shmget 函数返回的共享内存标识码
  • cmd:将要采取的动作,IPC_STAT:提取 shmid_ds 结构中的数据;IPC_SET:设置 shmid_ds 结构中的数据;IPC_RMID:删除共享内存
  • buf:指向一个保存着共享内存的模式状态和访问权限的数据结构

  毋庸置疑,共享内存可能存在多个必然是要先描述后组织起来的,shmid_ds 就是描述共享内存的结构体。它包括共享内存的大小、创建者和最后操作者的进程ID、当前有多少进程附加到这个共享内存段等属性。顺着往下找,其结构体内部的结构体 ipc_perm 中,就保存了由用户提供的 key 值。

四、消息队列和信号量(了解)

4.1 消息队列

  消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法,读端和写端公用一个队列。当发送方有数据发送时,将数据先打包成一个节点,然后尾插到内核中的消息队列中去。当接收方接收数据时,从队列头部开始去找所需要的节点,然后进行解包得到数据。同时每个数据块都会有个记录类型的数据,来判断该数据块该被哪个进程读取。

消息队列接口:使用几乎和共享内存一样,这里就不详细介绍了
获取:int msgget(key_t key, int msgflg);
控制:int msgctl(int msqid, int cmd, struct msqid_ds *buf);
发送: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);

4.2 信号量

信号量:
  信号量本质上就是个计数器,它统计的是公共资源资源的剩余量。而公共资源可以被多个进程同时访问,如果访没有同步与互斥,就会导致数据不一致问题(一个进程还在写的时候另一个进程就开始读)。而这种通过同步与互斥被保护起来的资源称为临界资源,访问临界资源的那部分代码称为临界区,其他的代码就称为非临界区。
互斥:当有多个执行流想要访问同一份资源的时候,我们只允许一个执行流进行访问,当这个执行流访问完了,下一个执行流能访问
  进程在访问公共资源前要先申请信号量,需要让多个进程看到同一个计数器,避免资源不足而访问失败。看到同一个计数器说明信号量也是个公共资源,也需要保护,因此对信号量的 pv 操作必须是原子的
P 操作:申请信号量,计数器减 1
V 操作:释放信号量,计数器加 1

原子性:要么不做,要么做完,只有这两种状态的情况

4.3 system V

  进程间通信除了通过管道,都是基于文件的通信方式,还有一种方式是:System V 标准的进程间通信方式。System V 标准是一个在OS层面专门为进程通信设计的一个方案,它是被精心设计过的。system V IPC 提供的通信方式有三种: 共享内存、消息队列和信号量,你可以发现它们的系统调用接口都非常相似,同时它们都有描述自己字段的结构体 xxx_ds。而在它们的 xxx_ds 结构体中,开头都有一个共同的字段 ipc_perm,这个 ipc_perm 类似于基类,被其它子类继承下去

	struct ipc_perm {key_t          __key;    /* Key supplied to shmget(2) */uid_t          uid;      /* Effective UID of owner */gid_t          gid;      /* Effective GID of owner */uid_t          cuid;     /* Effective UID of creator */gid_t          cgid;     /* Effective GID of creator */unsigned short mode;     /* Permissions + SHM_DEST and  SHM_LOCKED flags */unsigned short __seq;    /* Sequence number */};

  因为它们的第一个字段 ipc_perm 是一样的,所以可以维护一个 struct ipc_perm* 的指针数组,存共享内存、消息队列、信号量它们三者中,第一个元素的地址,也就是 &ipc_perm。这样就可以把共享内存、消息队列和信号量三个部分直接管理起来了。而我们知道结构体的第一个成员的地址和结构体对象的地址在数值上是相同的,并且操作系统在内部可以识别这个对象是共享内存、消息队列和信号量中的哪一个,因此我们拿到这个数组中的 ipc_perm 地址便能访问这结构体的其它成员,将它们管理起来

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

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

相关文章

VirtualSurveyor9.0.3 无人机测绘软件功能介绍

Virtual Surveyor9.0.3中文版是功能强大的无人机测绘软件,使用旨在为用户提供完整的地理空间数据可视化和分析功能,带来提高的生产力,功能全面而强大,在无人机到CAD模型的过程中,使用Virtual Surveyor软件来拆卸输送机…

情绪稳定的人有什么特点?

第一部分:至纯之人,大器晚成 1.1 单纯,不是天真 你知道吗?那些能够成就大事的人,往往在人性上非常单纯。他们对外界的需求很低,更多的是向内寻求。这样的人,他们的内心世界像一片净土&#xff…

数据结构与算法--顺序表(Java)

📝个人主页🌹:誓则盟约 ⏩收录专栏⏪:Java SE 🤡往期回顾🤡:Java SE--基本数据类型(详细讲解) 🌹🌹期待您的关注 🌹🌹 什么…

每日任务:TCP/IP模型和OSI模型的区别

介绍一下TCP/IP模型和OSI模型的区别? OSI模型由国标准化组织提出,而TCP/IP模型是由美国国防部开发的; OSI模型由七个层次组成,从下到上依次为物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。而TCP/IP模型只有四层…

AI视频生成(即梦)

1.打开即梦网页版 https://jimeng.jianying.com/ai-tool/home 2.图片生成-导入参考图(这里原本的红色或者灰度图都是可以的)-精细度5(最高图质量越高) 注:根据需要,选择不同的生图模型,具有…

线上监控诊断 - Arthas

简介 Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并且能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,…

SAPUI5基础知识20 - 对话框和碎片(Dialogs and Fragments)

1. 背景 在 SAPUI5 中,Fragments 是一种轻量级的 UI 组件,类似于视图(Views),但它们没有自己的控制器(Controller)。Fragments 通常用于定义可以在多个视图中重用的 UI 片段,从而提…

项目实战1(30小时精通C++和外挂实战)

项目实战1(30小时精通C和外挂实战) 01-MFC1-图标02-MFC2-按钮、调试、打开网页05-MFC5-checkbox及按钮绑定对象06--文件格式、OD序列号08-暴力破解09-CE10-秒杀僵尸 01-MFC1-图标 这个外挂只针对植物大战僵尸游戏 开发这个外挂,首先要将界面…

FPGA:流水灯设计

本次基于FPGA实现流水灯,即让LED[0:7]从左到右依次电量,每个LED灯频闪周期为1s钟,在这里,给出下面三种实现思路: 1、实验思路 1、使用位运算符 在复位时令LED灯为LED8’b0000_0001,然后每过一秒钟&#x…

软考:软件设计师 — 7.软件工程

七. 软件工程 1. 软件工程概述 (1)软件生存周期 (2)软件过程 软件开发中所遵循的路线图称为 "软件过程"。 针对管理软件开发的整个过程,提出了两个模型:能力成熟度模型(CMM&#…

嵌入式C++、STM32、MySQL、GPS、InfluxDB和MQTT协议数据可视化:智能物流管理系统设计思路流程(附代码示例)

目录 项目概述 系统设计 硬件设计 软件设计 系统架构图 代码实现 1. STM32微控制器与传感器代码 代码讲解 2. MQTT Broker设置 3. 数据接收与处理 代码讲解 4. 数据存储与分析 5. 数据分析与可视化 代码讲解 6. 数据可视化 项目总结 项目概述 随着电子商务的快…

简单小案例分析

一、容器和实例关系 <div class"app"><h1>Hello,{{name}}</h1> </div> <div class"app"><h1>Hello,{{name}}</h1> </div><script>//创建Vue实例new Vue({el:".app", //el用于指定当前V…

暴风骑士S9电摩上市,定义青少年骑行安全新标准

暴风骑士&#xff0c;作为全球高端儿童电动车的开创品牌&#xff0c;以其卓越的技术实力和创新精神&#xff0c;不断推动行业发展。如今&#xff0c;暴风骑士再次突破自我&#xff0c;推出了全新力作——S9青少年电摩。这款全新上市的青少年专属电摩&#xff0c;以其领先的安全…

LCD 横屏切换为竖屏-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

LCD 横屏切换为竖屏 横屏显示如何切换为竖屏显示 LCD 屏默认横屏显示 开发板配套的 LCD 屏默认都是横屏显示&#xff0c;如 4.3 寸、7 寸和 10.1 寸的不同分辨率的 RGB LCD 屏 固定坐标体系 &#xff08;以 800*480 分辨率为例&#xff09;横屏模式下的固定坐标&#xff1a;…

某数据泄露防护(DLP)系统NoticeAjax接口SQL注入漏洞复现 [附POC]

文章目录 某数据泄露防护(DLP)系统NoticeAjax接口SQL注入漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现某数据泄露防护(DLP)系统NoticeAjax接口SQL注入漏洞复现 [附POC] 0x01 前言 免责声明:请勿利用文章内…

Vitis AI 使用 VAI_Q_PYTORCH 工具

目录 1. 简介 2. 资料汇总 3. 示例解释 3.1 快速上手示例 4. 总结 1. 简介 vai_q_pytorch 是 Vitis AI Quantizer for Pytorch 的缩写&#xff0c;主要作用是优化神经网络模型。它是 Vitis AI 平台的一部分&#xff0c;专注于神经网络的深度压缩。 vai_q_pytorch 的作用…

如何应对SQL注入攻击?

引言 在现今的网络世界中&#xff0c;安全性已成为至关重要的话题。SQL注入&#xff08;SQL Injection&#xff09;是一种常见且危险的网络攻击方式&#xff0c;攻击者通过向SQL查询中插入恶意代码来操控数据库&#xff0c;从而获取敏感信息或破坏数据。了解SQL注入的各种类型…

2024中国大学生算法设计超级联赛(2)

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;陈童学哦&#xff0c;彩笔ACMer一枚。 &#x1f3c0;所属专栏&#xff1a;杭电多校集训 本文用于记录回顾总结解题思路便于加深理解。 &#x1f4e2;&#x1f4e2;&#x1f4e2;传送门 A - 鸡爪解题思…

AI在Facebook的应用:预见智能化社交的新前景

在数字化时代&#xff0c;社交媒体平台已成为我们生活的重要组成部分&#xff0c;而人工智能&#xff08;AI&#xff09;的快速发展正推动着这些平台向更智能、更个性化的方向发展。Facebook&#xff0c;作为全球最大的社交网络平台之一&#xff0c;正不断探索和应用AI技术&…

MySQL作业四

1. 创建数据库mydb15_indexstu 2. 创建表student&#xff0c;course&#xff0c;sc 2.1 创建表student 2.2 创建表course 2.3 创建表sc 3. 处理表 3.1 修改表student中年龄&#xff08;sage&#xff09;字段属性&#xff0c;数据类型由int改变为smallint 3.2 为表course中cno…