ToB企服应用市场:ToB评测及商务社交产业平台

标题: Linux :历程间通信之管道 [打印本页]

作者: 我爱普洱茶    时间: 2024-11-19 06:16
标题: Linux :历程间通信之管道


一、历程间通信

1.1 是什么和为什么

1、历程间通信是什么??
——>两个或多个历程实现数据层面的交互,但是由于历程独立性的存在,导致通信的本钱比较高。
2、既然通信本钱高,那为什么还要通信呢??
——> 在某些场景下我们必要差别历程之间举行(1)基本数据的交互。(2)发送下令。(3)实现某种协同。(4)通知某些信息……
1.2 如何实现历程间通信 

1、历程间通信的本质:要想办法让差别的历程看到同一份资源(以特定形式存在的内存空间)! 

2、这个资源必须由操作系统提供!!
问题: 为什么必须由操作系统提供呢??难道不能由此中一个历程提供么??
——>假设由一个历程提供,而我们又让另一个历程看到这份资源,那么这份资源应该属于谁呢?? ——>所以这种做法会破坏历程的独立性!!所以我们必须必要第三方空间,因此只能由操作系统提供!
      举个例子:保持历程独立性,可以理解为就是我俩不能见面,就好比说一个绑匪把你绑架了,但是他并不会直接去你家取赎金,也不会让你家人把赎金送到自己的住所,而是会要求你的家人把钱放到一个地方,然后你再去取。
 3、我们历程访问这个空间,本质上就是在访问操作系统!!
 ——>因为历程代表的就是用户,而操作系统并不相信用户,所以“资源”从创建、使用再到开释,必须使用系统调用接口!! 
4、一般操作系统,会有一个独立的通信模块——附属于文件系统——IPC通信模块  此中有两套尺度 system V && posix
5、基于文件级别的通信方式——管道 
 1.3 历程间通信的方案设计

     历程是具有独立性的,但是早期有的人发现我们很多时间必要通信,比假如历程必要通信,网络也必要通信,所以大家发现通信很紧张,另一方面由于通信模块的设计相对简单,且可实现方案多样化,因此大家你做你的,我做我的,导致现在很多Linux发型版本都不一样,纵然一样,内部的尺度也不一样!  
     因此当市面上出现了各种各样的通信方案后,我们必要做两件事 (1)选择一个最符合的方案。(2)必要去定制一个尺度(如许逼迫大家都遵守这个规则,差别的操作系统在设计的时间就不会有太大差别!!)
 ——>互联网行业尺度非常紧张,就好比为什么你的华为手机和苹果手机差别很大,但是却能实现通信! 就是因为各个领域都会有佼佼者在定制互联网尺度!如许才气包管设备之间的通信!!    ——>所以尺度假如没订定好,往小了说就是功能交互实现不了,往大了说互联网和物联网都实现不了!! 所以技能无论再怎么自由,背后都必须遵循一套尺度,否则就是不入流!
      但是这个尺度如何订定呢??大概很多差别的机构和公司都提供了差别的通信方案,而定制尺度是有版权的,就比如说有的尺度用的是西欧的尺度,就得付专利费,所以大家都在争这个,谁也不平谁(但其实无非就是代码有点差别)。但是尺度肯定不是谁想定就能定的 必须满足(1)本领强且德高望重 (2)技能方案特殊成熟,可以让其他人自愧不如!
 1.4 历程通信的分类

   管道:
  匿名管道pipe
  命名管道
    System V IPC:
  System V 消息队列
  System V 共享内存
  System V 信号量
    POSIX IPC:
  消息队列
  共享内存
  信号量
  互斥量
  条件变量
  读写锁
  1.5 历程通信的目的 

数据传输:一个历程必要将它的数据发送给另一个历程
资源共享:多个历程之间共享同样的资源。
通知事件:一个历程必要向另一个或一组历程发送消息,通知它(它们)发生了某种事件(如历程停止 时要通知父历程)。
历程控制:有些历程希望完全控制另一个历程的执行(如Debug历程),此时控制历程希望可以大概拦截另 一个历程的所有陷入和非常,并可以大概及时知道它的状态改变。
1.6 一些现状

       大部分互联网公司其实都想做一些低本钱高收入的应用,想赚快钱,其实对研发一些新东西的使命感很低。 
      假如做社会导向的一些业务是值得恭敬,但是很多公司并没有这种魄力,因为一旦产业路径形成后,后期就很那去转型。
      在这方便比较有责任使命感的是华为,因为华为一方面在做一些商业化的东西,一方面也会去搞研发,他其实推动了国内很多东西的发展,比如鸿蒙、芯片…… 区别就是不会像别的公司一样,别人用什么就用什么。
二、管道文件

2.1 管道的原理

        既然一个文件可以被多个历程打开,那么文件其实就算是一个公共资源,其实也可以做到一个历程读一个历程写,从而实现通信
——>但是如许会有一个问题,就是数据必须要写到外设上,所以就会有用率方面的问题
——>因此我们希望这个通信能在内存内里去举行而不牵扯到外设,所以我们必要有一个“内存级文件”概念(让用户可以大概通过扫描目录布局看到文件,但是只存在于内存中),然后我们必要让操作系统知道不要把内存级文件刷到磁盘上。而是只保留在缓冲区里。 

 ——>管道就是一个内存级文件,此中又根据方案的差别,存在匿名管道命名管道!
2.2 匿名管道

      接下来我们要思考的就是,我们究竟如何让两个历程看到同一份资源并实现通信,所以第一个方案就是——>父子历程!!因为子历程可以做到和父历程看到同一份代码,所以可以尝试让父历程和子历程举行通信!
       创建子历程的时间,pcb和文件描述符表,肯定是要拷贝的,但是并不会创建新的文件!!因为历程管理和文件系统是两个模块(你能打开我是因为操作系统,你还敢要求这么多??我们是平级!!)
    但是常规的文件固然可以被看到,但是必然会被刷新到磁盘上,所以我们不想让他刷新的话,就必须引入“内存级文件”——匿名管道,如许操作系统能区分开来

用fork来共享管道原理:

站在文件描述符角度-深度理解管道:

问题1:父历程和子历程一个读一个写实现了通信,但是假如此中一方不小心关掉了会不会导致另一方出错呢??
——>理论上是有大概的,但是操作系统已经考虑到了,就是通过引用计数
问题2:管道文件是只读方式打开的。所以子历程继续的时间也只有只读权限,那么两个都是读就没办法通信了吗??
——>所以我们必然不能在父历程中用open打开这个文件,而是用pipe这个专门为管道文件设置的接口,  普通文件必要通过open打开,而管道文件在设计的时间得用pipe,一边以只读方式打开,一边以只写的方式打开(占据了两个fd的位置),然后关掉此中一个不用的,然后继续给子历程也关掉一个不用的,最后实现父子历程一个是写端一个是读端的单向通信(这就是管道这个名字的由来)。
——>管道在设计的时间就是不能支持同时读写的!
——>另一方面 open是有路径的,因为他是一个真实存在的文件,而我们假如想打开一个内存级文件,就必须用接口pipe! 


       参数是一个 pipefd[2] 输出型参数 他会在该历程的文件描述符表中找到两个下标最小的位置,然后一个为读端打开的fd 放在pipefd[0]中  一个为写端打开的fd 放在pipefd[1]中  如许用户可以通过这个输出型参数拿到fd  关掉此中一个不用的  然后举利用用 
     成功了返回0  不成功返回-1  

站在内核角度-管道本质:

     所以,看待管道,就犹如看待文件一样!管道的使用和文件一致,迎合了“Linux统统皆文件头脑”。  
2.3 匿名管道的设计

makefile: 


1、建立通信
2、实现读写方法  
 fd的规则就是 无论这个文件是什么文件 我们都可以去举行操作
问题:我们为什么不直接界说出全局变量,如许fork之后至子历程不就能看到了吗??
——>如许是继续而不是通信,因为我们要拿到的数据大概是会变革的,如许通信才故意义
 2.4 匿名管道的特征


1、具有血缘关系的历程举行历程间通信
2、管道只能单向通信(实现双向通信就必须有两个管道)
3、父子历程是会历程协同、同步与互斥的 ——>掩护管道文件的数据安全
        对于父历程来说,子历程写了多少次根本不紧张,只要管道里有数据,有多少就会读多少,前提条件是我们缓冲区充足大。也就是说,当子历程向管道写满了,当父历程在读的时间,就会把多次写的信息一次读了出来,在父历程看来,它读到的就是一个一个的字符,对于我们用户用什么存取,如何区分,这是我们用户的事。所以我们得出一个管道的特点,管道是面向字节流的
4、管道是面向字节流的
       写端写了自己,我不管,反正我读端默认会把整个缓存区都读出来(因为在我看来缓冲区就是一个个字节) 至于你要把读出来的这些怎么做分离,是你用户的事情,不是我这个管道应该操心的——>这种特点就是字节流
       就好比石油管道,无论你放多少石油,我都会流向出口,但是你在出口是要用碗接,照旧用桶接,我一点也不关心,那是你自己的事情
 ——>所以假如我们想改变这种字节流的话,比如说希望一次性只读取15个字节,那么就必要涉及到协议的知识!!
5、管道是有固定大小的(Linux中是64KB)且具有原子性,但是在差别的内核里大概有区别 
 验证管道大小:

最后写到65536说明管道大小是64kb 

ulimit 下令用于限定 shell 历程及其所创历程的资源使用

 ulimit -a检察到的pipe size一次原子写入为:512 bytes * 8 = 4096 bytes 。(4KB)
问题:可以我们验证的时间管道大小是64kb,那为什么pipesize是4kb呢??
——> 因为管道具有原子性!!pipesize的意思是管道一次原子写入的大小,意思就是只要你写入的内容不超过这个大小,那么在你写的期间,父历程不会来读!

 6、管道是基于文件的,而文件的生命周期是随历程的
 2.5 管道中的四种情况

1、读写端正常,管道假如为空,那么读端就会阻塞 (防止读入一些垃圾数据)
2、读写端正常,管道假如被写满,写端就要阻塞  (防止覆盖之前的数据)
——>父子历程是会历程协同的,同步和互斥的 都是为了掩护管道文件的数据安全!! 
3、读端正常读,写端关闭,读端最后会读到0,表明读到了文件pipe结尾,不会被阻塞!

所以读端(父历程读到0的时间)发现读到文件结尾,没有读的意义了 就可以break。
4、写端正常写入,但是读端关闭了,操作系统就要杀掉正在写入的历程——>通过信号杀掉!
   起首我们要知道,操作系统是不会做低效、浪费资源和时间等雷同的工作的,假如做了,操作系统就是bug;所以我们想,写端正常,读端关闭后,还有实际意义吗?没有了!因为写满了又怎样呢,又没有历程去读,所以当写端正常,读端关闭了,操作系统就要 kill 掉正在写入的历程。如何 kill 呢?通过信号,其实操作系统会使用13号信号 SIGPIPE kill 掉正在写入的历程

    所以为什么我们一般让父历程读子历程写呢??因为如许我们父历程可以在回收子历程的时间检测到子历程是被信号杀死的,照旧正常退出的!!

2.6 管道的应用场景 

       那么我们上面学的管道,和我们以前学过的哪些有关系呢?
1、起首我们以前接触过 | 这个符号,其实这个就是管道,比方我们在多条指令中使用 | :

     我们会发现他们的PID不一样,但是PPID是一样的,说明他们的父历程都是bash,而他们是具有血缘关系的历程,所以“ | ”就相当于操作系统为他们创建了匿名管道来实现通信!
 2、可以实现历程池(通过系统调用的的次数来提高内存的申请速度)
 所以,当父历程想布置任务的时间,无非就是做两件事,一就是选择任务,二是选择历程。
2.7 命名管道 

      上面我们学到的匿名管道是没有名字的,因为打开那个文件的时间并没有告诉我们文件名,也就是管道并没有命名。我们直接以读方式写方式打开父子历程,各自拿一个读写端就可以通行。正是因为它没有名字,那么所以匿名管道必须得让我们对应的父子历程看到通信资源,它采用的是让父子继续的方案看到的。
     假如毫不相关的历程举行历程间通信呢??所以我们必要有下一个方案叫做命名管道。接下来我们先使用一下命名管道,先看现象再表明。此中建立命名管道的接口为 mkfifo  

那么如何实现通信呢??我们创建两个终端,一个读一个写观察

 该管道看起来是在磁盘中存在,但是它实际数据并不会刷新到磁盘上。
 我们一直往管道里写,管道的大小都不会发生变革

问题1:父子历程可以通过继续看到同一个文件,那两个毫不相关的历程,我怎么知道这俩历程打开的是不是同一个文件呢??
——>同一路径下的文件名:路径+文件名 (唯一性)
命名管道有自己的名字,所以他的体系照旧跟文件如出一辙的体系,只不外区别是他不会刷盘!

问题2:假如两个历程打开同一个文件,在内核中,操作系统会打开几个文件呢??
——> 只会打开一个文件,维护一个缓冲区
      难道不怕两个历程写在缓冲区会混乱么??——>本身两个历程同时打开一个不受掩护的文件,纵然有两个缓冲区,写入也是会混乱的,所以你用户都不怕了,我操作系统怕什么??? 
 


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4