linux——IPC 进程间通信

 IPC   进程间通信  interprocess communicate

IPC(Inter-Process Communication),即进程间通信,其产生的原因主要可以归纳为以下几点:

进程空间的独立性

  1. 资源隔离:在现代操作系统中,每个进程都拥有自己独立的代码和数据空间。这种隔离机制确保了进程之间的安全性和稳定性,但同时也使得进程间无法直接访问对方的资源。

  2. 资源无法共享:由于进程空间的独立性,一个进程无法直接读取或修改另一个进程的内存空间中的数据。这种情况下,如果需要进行数据交换或共享资源,就需要通过特定的机制来实现。

进程间协作的需求

  1. 数据交换:在多进程操作系统中,不同的进程可能需要交换数据以完成共同的任务。例如,一个进程可能负责生成数据,而另一个进程则负责处理这些数据。为了实现这种数据交换,就需要使用IPC机制。

  2. 资源共享:进程间通信还允许进程共享资源,如文件、数据库、内存等。通过IPC,进程可以协调对共享资源的访问,避免冲突和竞争条件。

  3. 任务协调:在分布式系统或并发编程中,多个进程可能需要协同工作以完成复杂的任务。IPC提供了进程间同步和互斥的机制,确保任务能够按照预定的顺序和条件执行。

IPC的必要性

  1. 提高系统并发性:通过IPC,多个进程可以并行处理不同的任务,从而提高系统的并发处理能力。

  2. 优化资源利用:IPC允许进程共享资源,减少了资源的重复分配和浪费,提高了资源利用率。

  3. 实现复杂功能:在构建复杂的软件系统时,往往需要多个进程协同工作。IPC为这些进程之间的通信和协作提供了必要的支持。

IPC的实现方式

IPC的实现方式多种多样,包括但不限于以下几种:

  1. 管道(Pipe):一种单向通信方式,常用于具有亲缘关系的进程间通信。

  2. 消息队列(Message Queue):允许多个进程从同一个队列中读取数据,具有独立性和异步性。

  3. 共享内存(Shared Memory):一段可以被多个进程同时访问的物理内存区域,提高了进程间的数据交换效率。

  4. 信号(Signal):一个进程向另一个进程发送信号来传递某种信息或通知某个事件的发生。

  5. 套接字(Socket):用于不同主机之间的进程通信,提供了网络通信的能

管道==》无名管道、有名管道

    无名管道 ===》pipe ==》只能给有亲缘关系进程通信
    有名管道 ===》fifo ==》可以给任意单机进程通信


    管道的特性:
    1、管道是 半双工的工作模式(收或者发)
    2、所有的管道都是特殊的文件不支持定位操作。不支持lseek->> fd  fseek ->>FILE* 
    3、管道是特殊文件,读写使用文件IO。fgets,fread,fgetc,

       一般情况下使用open,read,write,close;

主要看是否是二进制文件,如果是文本文件使用fges之类的标准io。

注意事项:  
   1,读端存在,一直向管道中去写,超过64k,写会阻塞。(写的快,读的慢)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{int pipefd[2]={0};int ret = pipe(pipefd);if(-1 == ret){perror("pipe");exit(1);}pid_t pid = fork();if(pid>0){char buf[]="hello,world";close(pipefd[0]);sleep(3);write(pipefd[1],buf,strlen(buf));}else if(0 == pid){close(pipefd[1]);char buf[100]={0};read(pipefd[0],buf,sizeof(buf));printf("pipe %s\n",buf);}else {perror("fork");exit(1);}return 0;
}

   2,写端是存在的,读管道,如果管道为空的话,读会阻塞(读的快,写的慢)

    读阻塞和写阻塞都是正常情况。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{int pipefd[2]={0};int ret = pipe(pipefd);if(-1 == ret){perror("pipe");exit(1);}pid_t pid = fork();if(pid>0){char buf[1024]={0};close(pipefd[0]);memset(buf,'a',1024);int i = 0 ;for(i=0;i<65;i++){write(pipefd[1],buf,sizeof(buf));printf("i is %d\n",i);}}else if(0 == pid){close(pipefd[1]);char buf[100]={0};
//        read(pipefd[0],buf,sizeof(buf));//      printf("pipe %s\n",buf);while(1)sleep(1);}else {perror("fork");exit(1);}return 0;
}

  3.管道破裂,读端关闭,写管道。

(会导致写关闭,接收端关闭,导致发送端关闭)类似于段错误

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{int pipefd[2]={0};int ret = pipe(pipefd);if(-1 == ret){perror("pipe");exit(1);}pid_t pid = fork();if(pid>0){char buf[]="hello,world";close(pipefd[0]);sleep(3);// 管道破裂 gdb  跟踪write(pipefd[1],buf,strlen(buf));printf("aaaa\n");}else if(0 == pid){close(pipefd[1]);close(pipefd[0]);}else {perror("fork");exit(1);}return 0;
}


   4. read 0 ,写端关闭,如果管道没有内容,read 0 ;

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{int pipefd[2]={0};int ret = pipe(pipefd);if(-1 == ret){perror("pipe");exit(1);}pid_t pid = fork();if(pid>0){char buf[]="hello,world";close(pipefd[0]);write(pipefd[1],buf,strlen(buf));write(pipefd[1],buf,strlen(buf));close(pipefd[1]);}else if(0 == pid){close(pipefd[1]);char buf[5]={0};while(1){//memset(buf,0,5);bzero(buf,sizeof(buf));int rd_ret = read(pipefd[0],buf,sizeof(buf)-1);if(rd_ret<=0){break;}printf("pipe %s\n",buf);}}else {perror("fork");exit(1);}return 0;
}

 if(rd_ret<=0)
            {
                break;
            }

如果读端进程调用read()函数从管道中读取数据,并且管道已经为空(即没有任何待读取的数据),同时写端已经被关闭,那么read()函数将会立即返回,并且返回值为0。这个返回值0是一个特殊的信号,它告诉读端进程,管道的写端已经被关闭,并且管道中没有更多的数据可以读取了。

使用框架:
    创建管道 ==》读写管道 ==》关闭管道

1、无名管道 ===》管道的特例 ===>pipe函数
    特性:
    1.1  亲缘关系进程使用
    1.2  有固定的读写端

   

流程:
    创建并打开管道: pipe函数

先创建管道再fork();

关闭管道1或者0用,close(xx);
#include <unistd.h>
int pipe(int pipefd[2]);
功能:创建并打开一个无名管道
参数:pipefd[0] ==>无名管道的固定读端
      pipefd[1] ==>无名管道的固定写端
返回值:成功 0
        失败 -1;

注意事项:
    1、无名管道的架设应该在fork之前进行。
    
无名管道的读写:===》文件IO的读写方式。
    读: read()
    写: write()

关闭管道: close();

通过管道的方式实现文件的复制:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{int pipefd[2]={0};int ret = pipe(pipefd);if(-1 == ret){perror("pipe");exit(1);}pid_t pid = fork();if(pid>0){close(pipefd[0]);int fd =  open("/home/linux/1.png",O_RDONLY);if(-1 == fd){perror("open");exit(1);}while(1){char buf[4096]={0};int rd_ret = read(fd,buf,sizeof(buf));if(rd_ret<=0){break;}write(pipefd[1],buf,rd_ret);}close(fd);close(pipefd[1]);}else if(0 == pid){close(pipefd[1]);int fd = open("2.png",O_WRONLY|O_CREAT|O_TRUNC,0666);if(-1==fd){perror("open");exit(1);}while(1){char buf[1024]={0};int rd_ret = read(pipefd[0],buf,sizeof(buf));if(rd_ret<=0){break;}write(fd,buf,rd_ret);}close(fd);close(pipefd[0]);}else {perror("fork");exit(1);}return 0;
}


验证如下问题:
1、父子进程是否都有fd[0] fd[1],
   如果在单一进程中写fd[1]能否直接从fd[0]中读到。

   可以,写fd[1]可以从fd[0]读

2、管道的数据存储方式是什么样的
   数据是否一直保留?
    栈, 先进后出
   队列形式存储 读数据会剪切取走数据不会保留
   先进先出

3、管道的数据容量是多少,有没有上限值。
    操作系统的建议值: 512* 8 = 4k
    代码测试实际值:   65536byte= 64k

4、管道的同步效果如何验证?读写同步验证。
    读端关闭能不能写? 不可以 ===>SIGPIPE 异常终止 (触发管道破裂)
    写端关闭能不能读? 可以,取决于pipe有没有内容,===>read返回值为0 不阻塞

    结论:读写端必须同时存在,才能进行
          管道的读写。


5、固定的读写端是否就不能互换?
    能否写fd[0] 能否读fd[1]?   不可以,是固定读写端。

    
练习:
    如何用管道实现一个双向通信功能
    将从父进程发送的消息在发回给父
    进程。
    
    
    pipe,
    
    fork()
    
    if(pid>0)
    {
        read(file,,)
        wirte(fd[1]);
    }
    
    if(0 == pid)
    {
            read(fd[0]);
            write(newfile);
    }
    
    
    
    person
    {
        char name[];
        int age;
        char phone;
    }
    
    
    pipe[];
    fork();
    
    > 0
    fgets 获得输入
    填结构体,
    写入管道,
    ==0
    
    read,
    填结构体,,
    
    显示到。。。
    
    hello
    pipe:hello 
    wordld
    pipe2 ::world;
    
    
    
    
    
    

有名管道===》fifo ==》有文件名称的管道。
                      文件系统中可见

框架:
    创建有名管道 ==》打开有名管道 ==》读写管道
    ==》关闭管道  ==》卸载有名管道

1、创建:mkfifo
#include <sys/types.h>
#include <sys/stat.h>
 remove();

int mkfifo(const char *pathname, mode_t mode);
功能:在指定的pathname路径+名称下创建一个权限为
      mode的有名管道文件。
参数:pathname要创建的有名管道路径+名称
      mode  8进制文件权限。
返回值:成功 0
        失败  -1;

2、打开有名管道 open
    注意:该函数使用的时候要注意打开方式,
    因为管道是半双工模式,所有打开方式直接决定
    当前进程的读写方式。
    一般只有如下方式:
    int fd-read = open("./fifo",O_RDONLY); ==>fd 是固定读端
    int fd-write = open("./fifo",O_WRONLY); ==>fd 是固定写端

    不能是 O_RDWR 方式打开文件。
    不能有 O_CREAT 选项,因为创建管道有指定的mkfifo函数


3、管道的读写: 文件IO

    读: read(fd-read,buff,sizeof(buff));
    写: write(fd-write,buff,sizeof(buff));

4、关闭管道:
        close(fd);

5、卸载管道:remove();
        int unlink(const char *pathname);
        功能:将指定的pathname管道文件卸载,同时
              从文件系统中删除。
        参数: ptahtname 要卸载的有名管道 
        返回值:成功 0
                失败  -1;

open会阻塞,等到另一端读端打开,解除阻塞。

函数是否会阻塞,具体根据操作的对象有关。


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
int main(int argc, char *argv[])
{int ret = mkfifo("myfifo",0666);    if(-1 == ret){//如果是管道文件已存在错误,让程序继续运行if(EEXIST== errno){}else {perror("mkfifo");exit(1);}}//open 会阻塞,等到另一端读段打开,解除阻塞int fd = open("myfifo",O_WRONLY);if(-1 == fd){perror("open");exit(1);}char buf[256]="hello,fifo,test";write(fd,buf,strlen(buf));close(fd);return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>int main(int argc, char *argv[])
{int ret = mkfifo("myfifo",0666);    if(-1 == ret){//如果是管道文件已存在错误,让程序继续运行if(EEXIST== errno){}else {perror("mkfifo");exit(1);}}int fd = open("myfifo",O_RDONLY);if(-1 == fd){perror("open");exit(1);}char buf[256]={0};read(fd,buf,sizeof(buf));printf("fifo %s\n",buf);close(fd);//remove("myfifo");return 0;
}

remove可以在命令行调用。

运行方法:

练习:
    编写一个非亲缘关系进程间通信程序,可以从
    A程序向B程序连续发送不同的数据,并从B中
    将发送的信息打印输出,当双方收到quit的时候
    程序全部退出。

思考题:
    是否每次启动程序必须进行有名管道的创建工作
    能否有一个独立的维护工具,可以任意创建并删除
    有名管道?
    比如:
        ./fifo_tool -A fifo  ==>创建一个有名管道fifo
        ./fifo_tool -D fifo  ==>删除一个有名管道fifo

作业:

    有名管道的操作函数封装:
    int fifo_read(char *fifoname,void *s,int size);
    int fifo_write(char *fifoname,void *s,int size);

    编写测试程序验证以上两个函数效果。

    gstream

  有名管道 ===》

    1、是否需要同步,以及同步的位置。
        读端关闭 是否可以写,不能写什么原因。
        写端关闭 是否可以读。

        结论:有名管道执行过程过必须有读写端同时存在。
              如果有一端没有打开,则默认在open函数部分阻塞。

    2、有名管道是否能在fork之后的亲缘关系进程中使用。
        结论: 可以在有亲缘关系的进程间使用。
        注意: 启动的次序可能会导致其中一个稍有阻塞。

    3、能否手工操作有名管道实现数据的传送。
        读: cat  fifoname
        写: echo "asdfasdf" > fifoname

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ValidateAntiForgeryToken、AntiForgeryToken 防止CSRF(跨网站请求伪造)

用途&#xff1a;防止CSRF&#xff08;跨网站请求伪造&#xff09;。 用法&#xff1a;在View->Form表单中: aspx&#xff1a;<%:Html.AntiForgeryToken()%> razor&#xff1a;Html.AntiForgeryToken() 在Controller->Action动作上&#xff1a;[ValidateAntiForge…

SSM少儿读者交流系-计算机毕业设计源码20005

摘要 随着信息技术的发展和互联网的普及&#xff0c;少儿读者之间的交流方式发生了革命性的变化。通过使用Java编程语言&#xff0c;可以实现系统的高度灵活性和可扩展性。而SSM框架的采用&#xff0c;可以提供良好的开发结构和代码管理&#xff0c;使系统更加稳定和易于维护。…

基于Springboot的智慧信息化机房管理系统

1 项目介绍 1.1 研究目的和意义 随着社会的快速发展&#xff0c;计算机的影响是全面且深入的。人们生活水平的不断提高&#xff0c;日常生活中人们对高校共享机房管理方面的要求也在不断提高&#xff0c;需要高校共享机房的人数更是不断增加&#xff0c;使得高校共享机房管理…

向量数据库、主键存储引擎、高速网络 RDMA 框架……DolphinDB 版本更新啦!

盛夏已至&#xff0c;炎热的七月伊始&#xff0c;DolphinDB 也迎来了版本的更新。此次更新的 3.00.1 与 2.00.13 版本从多个维度进行了优化扩展&#xff0c;进一步深化了 DolphinDB 在机器学习、数据分析等领域的尝试与探索。 为了响应用户日益增长的 AI 运算需求&#xff0c;…

idea Git操作

1、代码拉取&#xff08;左上角&#xff09; 或 2、代码push&#xff08;左上角&#xff09; 3、切换分支&#xff08;右下角&#xff09; 4、分支管理 5、当前分支和某一个分支对比差异 6、当前分支某一个提交需要恢复成提交前状态&#xff08;revert&#xff09; 7、其他分…

大疆2025校招内推

需要内推码的请留言哦 期待你的加入

改变conda创建虚拟环境时的默认路径(C盘)

①C:\Users\Lenovo 找到C盘中用户目录下的.condarc文件 ②打开.condarc文件后&#xff0c;添加并修改.condarc 中的 env_dirs 环境路径&#xff0c;按顺序第⼀个路径作为默认存储路径&#xff0c;也就是我的E盘&#xff08;需要你先在E盘中新建文件夹envsE&#xff09;。修改完…

LabVIEW新能源汽车电池性能测试系统

新能源汽车的核心部件之一是电池&#xff0c;其性能直接关系到整车的续航里程、安全性和寿命。为了确保电池的性能和可靠性&#xff0c;测试是必不可少的环节。本文介绍了一种基于LabVIEW的新能源汽车电池性能测试系统&#xff0c;通过LabVIEW与数据采集设备的无缝集成&#xf…

【web APIs】快速上手Day05(Bom操作)

目录 Web APIs - 第5天笔记js组成window对象BOM定时器-延迟函数案例-5秒钟之后消失的广告 JS执行机制location对象案例-5秒钟之后跳转的页面 navigator对象histroy对象 本地存储&#xff08;今日重点&#xff09;localStorage&#xff08;重点&#xff09;sessionStorage&#…

JAVA数字化产科管理平台源码:涵盖了孕妇从建档、产检、保健、随访、分娩到产后42天全流程的信息化管理

JAVA数字化产科管理平台源码&#xff1a;涵盖了孕妇从建档、产检、保健、随访、分娩到产后42天全流程的信息化管理 智慧产科管理系统是基于自主研发妇幼信息平台&#xff0c;为医院产科量身打造的信息管理系统&#xff0c;涵盖了孕妇从建档、产检、保健、随访、分娩到产后42天全…

米国政府呼吁抛弃 C 和 C++

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「C的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; 很多观点认为C 或 C永远不可被…

Django 模版继承

1&#xff0c;设计母版页 Test/templates/6/base.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><!-- 修正了模板标签的全角字符问题 -->{% block title %}<title>这个是母版页</title>{…

记录一下简单导入导出excel二级表头

数据库导入导出表头 之前的工具类GenerateExcelToFile新增两个导出这种二级表头方法 package com.njry.utils;import cn.hutool.core.util.IdUtil; import com.njry.config.FileProperties; import com.njry.exception.BadRequestException; import org.apache.poi.hssf.user…

Spring Cloud Alibaba - Sentinel 分布式系统流量哨兵

目录 概述特征基本概念 安装Sentinel微服务引入Sentinel案例流控规则&#xff08;流量控制&#xff09;流控模式-直接流控模式-关联流控模式-链路流控效果-快速失败流控效果-预热WarmUp流控效果-排队等候 流控规则&#xff08;并发线程数控制&#xff09;熔断规则&#xff08;熔…

【多媒体】富客户端应用程序GUI框架 JavaFX 2.0 简介

JavaFX 最初是由 Oracle 推出的一个用于开发富客户端应用程序的框架&#xff0c;它提供了丰富的用户界面控件、布局容器、3D图形绘制、媒体播放和动画等功能&#xff0c;旨在取代较旧的 Swing 框架。JavaFX 于 2007 年推出&#xff0c;2011 年 10 月发布了2.0 版本。JavaFX 2.0…

数据结构(一)C语言补

数据结构 内存空间划分 一个进程启动后&#xff0c;会生成4G的内存空间 0~3G是用户空间(应用层) 3~4G是内核空间(底层) 0~3G 3~4G 所有的进程都会共享3G~4G的内核空间&#xff0c; 但是每个进程会独立拥有0~3G的用户空间。 栈区 存放数据特点 栈区存放数据的申请空间的先后…

小学vr虚拟课堂教学课件开发打造信息化教学典范

在信息技术的浪潮中&#xff0c;VR技术正以其独特的魅力与课堂教学深度融合&#xff0c;引领着教育方式的创新与教学方法的变革。这一变革不仅推动了“以教促学”的传统模式向“自主探索”的新型学习方式转变&#xff0c;更为学生带来了全新的学习体验。 运用信息技术融合VR教学…

C++那些事之小项目实战-进程间通信

小项目实战之进程间通信 进程间通信是一个非常重要的话题&#xff0c;特别是像一些大型项目都有它的影子&#xff0c;例如&#xff1a;PostgreSQL使用了管道完成copy的进程间通信&#xff0c;那么本节也将基于这个主题&#xff0c;使用C去搭建一个进程间通过管道通信的demo出来…

【代码随想录】【算法训练营】【第53天】 [739]每日温度 [496]下一个更大元素I [503]下一个更大元素II

前言 思路及算法思维&#xff0c;指路 代码随想录。 题目来自 LeetCode。 day 48&#xff0c;周六&#xff0c;不能再坚持~ 题目详情 [739] 每日温度 题目描述 739 每日温度 解题思路 前提&#xff1a;寻找任一个元素的右边比自己大的元素的位置 思路&#xff1a;通常…