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

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Hadoop-12-Hive 基本介绍 下载安装配置 MariaDB安装 3台云服务Hadoop集群 架构图 对比SQL HQL

章节内容 上一节我们完成了&#xff1a; Reduce JOIN 的介绍Reduce JOIN 的具体实现DriverMapperReducer运行测试 背景介绍 这里是三台公网云服务器&#xff0c;每台 2C4G&#xff0c;搭建一个Hadoop的学习环境&#xff0c;供我学习。 之前已经在 VM 虚拟机上搭建过一次&am…

独立开发者系列(18)——js的window对象

独立开发者&#xff0c;必然要面对JS代码&#xff0c;基本可以认为在脚本语言里面&#xff0c;JS门槛最低&#xff0c;正因为如此&#xff0c;JS也是最受欢迎的开发语言之一。JS的代码运行规律&#xff0c;按照代码模块执行&#xff0c;也就是<script></script> 每…

2024年上半年网络工程师下午真题及答案解析

试题一(20分) 某高校网络拓扑如下图所示&#xff0c;两校区核心&#xff08;CORE-1、CORE-2&#xff09;&#xff0c;出口防火墙&#xff08;NGFW-1、NGFW-2&#xff09;通过校区间光缆互联&#xff0c;配置OSPF实现全校路由收敛&#xff0c;两校区相距40km。两校区默认由本地…

「媒体邀约」苏州媒体宣传服务公司

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体宣传加速季&#xff0c;100万补贴享不停&#xff0c;一手媒体资源&#xff0c;全国100城线下落地执行。详情请联系胡老师。 苏州的媒体资源相当丰富&#xff0c;涵盖了报纸、电视、广…

postman请求访问:认证失败,无法访问系统资源

1、使用postman时&#xff0c;没有传入相应的token&#xff0c;就会出现这种情况&#xff0c;此时需要把token放进去 发现问题: { "msg": "请求访问&#xff1a;/getInfo&#xff0c;认证失败&#xff0c;无法访问系统资源", "code": 401 } 1…

金属制品行业企业数字化转型实践

金属制品行业总体上存在着企业数量多、规模小、管理流程复杂等特点。而在数字化应用方面&#xff0c;调查显示&#xff1a;金属制品行业企业信息化总体应用水平低&#xff0c;信息系统建设水平尚处于一般事务处理和简单信息管理阶段&#xff0c;“信息孤岛”问题严重。在信息化…

最新发布!MySQL 9.0 的向量 (VECTOR) 类型文档更新

7月1日&#xff0c;MySQL 9.0.0 创新版本, 8.4.1 LTS, 8.0.38 三版齐发。 发版当天安装包已经可以下载&#xff0c;我也在第一时间做了分享&#xff1a; MySQL 9.0.0 新鲜出炉&#xff01;支持向量类型 当时参考手册还未上线&#xff0c;这两天文档虽已上线&#xff0c;但似乎仍…

RPM包管理-rpm命令管理

1.RPM包命令原则 所有的rpm包都在光盘中 例&#xff1a;httpd-2.2.15-15.e16.centos.1.i686.rpm httpd 软件包名 2.2.15 软件版本 15 软件发布的次数 e16.centos 适合的Linux平台 i686 适合的硬件平台…

springboot酒店管理系统-计算机毕业设计源码93190

目 录 摘 要 1 绪论 1.1 选题背景与意义 1.2开发现状 1.3论文结构与章节安排 2 酒店管理系统系统分析 2.1 可行性分析 2.1.1 技术可行性分析 2.1.2 经济可行性分析 2.1.3 法律可行性分析 2.2 系统功能分析 2.2.1 功能性分析 2.2.2 非功能性分析 2.3 系统用例分析…

【计算机视觉】基于OpenCV的直线检测

直线检测原理 霍夫变换是图像处理必然接触到的一个算法&#xff0c;它通过一种投票算法检测具有特定形状的物体,该过程在一个参数空间中通过计算累计结果的局部最大值得到一个符合该特定形状的集合作为霍夫变换结果&#xff0c;该方法可以进行圆&#xff0c;直线&#xff0c;椭…

docker安装ElasticSearchKibana

本文参考以下两篇文章 ✅ElasticSearch&Kibana 部署 云效 Thoughts 企业级知识库 (aliyun.com) docker安装ElasticSearch&Kibana - 飞书 安装elasticsearch 使用docker下载es&#xff1a; docker pull elasticsearch:8.13.0 挂载配置 创建挂在文件目录 mkdir…

Hadoop3:集群压测-读写性能压测

一、准备工作 首先&#xff0c;我们要知道&#xff0c;平常所说的网速和文件大小的MB是什么关系。 100Mbps单位是bit&#xff1b;10M/s单位是byte ; 1byte8bit&#xff0c;100Mbps/812.5M/s。 测试 配置102、103、104虚拟机网速 102上用Python开启一个文件下载服务&#x…

职升网:注会考试科目搭配策略建议!

一、CPA考试特点概述 CPA&#xff08;注册会计师&#xff09;考试是一个综合性极强的考试&#xff0c;分为专业阶段和综合阶段。专业阶段涵盖了《会计》、《审计》、《财务成本管理》、《税法》、《经济法》和《公司战略与风险管理》六大科目。这些科目不仅知识点繁多&#xf…

轻松搞定Docker!教你一键删除所有镜像!

大家好,我是CodeQi! 一位热衷于技术分享的码仔。 Docker 是一种流行的容器化平台,它提供了一种轻量级且可移植的方式来打包、分发和运行应用程序。 在使用 Docker 进行应用程序开发和部署时,我们通常会创建和使用各种镜像。然而,随着时间的推移,我们可能会积累大量的镜…

Ubuntu TensorRT安装

什么是TensorRT 一般的深度学习项目&#xff0c;训练时为了加快速度&#xff0c;会使用多 GPU 分布式训练。但在部署推理时&#xff0c;为了降低成本&#xff0c;往往使用单个 GPU 机器甚至嵌入式平台&#xff08;比如 NVIDIA Jetson&#xff09;进行部署&#xff0c;部署端也…

Keil用ST-LINK下载STM32程序后不自动运行

之后程序可以运行了&#xff0c;但是串口还没有输出&#xff0c;在debug模式下都是ok的。

Richtek立锜科技车规级器件选型

芯片按照应用场景&#xff0c;通常可以分为消费级、工业级、车规级和军工级四个等级&#xff0c;其要求依次为军工>车规>工业>消费。 所谓“车规级元器件”--即通过AEC-Q认证 汽车不同于消费级产品&#xff0c;会运行在户外、高温、高寒、潮湿等苛刻的环境&#xff0c…

重磅!首本大模型中文新书发布,复旦最新《大规模语言模型·从理论到实践》,理论+代码

复旦大学自然语言处理实验室张奇教授、桂韬研究员、郑锐博士生以及黄萱菁教授结合之前在自然语言处理领域研究经验&#xff0c;以及分布式系统和并行计算的教学经验&#xff0c;通过在大语言模型实践和理论研究的过程中&#xff0c;历时 8 个月完成本书《大规模语言模型从理论到…

【数学建模】 数据处理与拟合模型

文章目录 数据处理与拟合模型1. 数据与大数据1.1 什么是数&#xff1f;什么是数据&#xff1f;1.2 数据与大数据1.3 数据科学的研究对象 2. 数据的预处理2.1 为什么需要数据预处理2.2 使用pandas处理数据的基础2.3 pandas常用方法总结2.4 数据的规约1) 维度规约2) 数值规约3) 数…

Excel中按列的首行字母顺序,重新排列(VBA脚本)

排序前 要求对4列数据按照第一行abcd的顺序排列 VB脚本如下&#xff1a; 要使用这个脚本&#xff0c;请按照以下步骤操作&#xff1a; 打开Excel&#xff0c;然后按下 Alt F11 打开VBA编辑器。在VBA编辑器中&#xff0c;选择“插入” > “模块”&#xff0c;在打开的模块…