linux——IPC 进程间通信

news2024/11/16 4:21:20

 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.coloradmin.cn/o/1892442.html

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

相关文章

《野孩子》:撤档背后的故事与思考

《野孩子》&#xff1a;撤档背后的故事与思考 2024年7月&#xff0c;一部备受期待的电影《野孩子》原定于全国上映&#xff0c;却因后期进度原因不得不宣布撤档。这部电影由知名导演殷若昕执导&#xff0c;当红小生王俊凯领衔主演&#xff0c;讲述了两个命运相似的少年相依为命…

“proxy_pass“ directive is duplicate

后面发现是nginx.conf里面proxy pass这里有两个&#xff0c;注释其中一个并重新运行即可&#xff01;

【QT】常用控件|QLabel|QLCDNumber|QProgressbar|QCalenderWidget

目录 ​编辑 QLabel 核心属性 testFormat 自适应pixmap 文本对齐&#xff0c;换行 Buddy QLCDNumber 核心属性 倒计时 处理槽函数 QProgressbar 核心属性 QCalendarWidget 核心属性 核心信号 QLabel 用来显示文本和图片 核心属性 属性作用textFormat 文本的格…

CSS-实例-div 水平居中 垂直靠上

1 需求 2 语法 3 示例 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>表格水平居中、垂直靠上示例…

2023年问界M9 EV 问界M9增程维修手册和电路图线路图资料更新

此次更新了2023年问界M9 EV及问界M9增程维修手册和电路图资料&#xff0c;覆盖市面上99%车型&#xff0c;包括维修手册、电路图、新车特征、车身钣金维修数据、全车拆装、扭力、发动机大修、发动机正时、保养、电路图、针脚定义、模块传感器、保险丝盒图解对照表位置等等&#…

python-计算矩阵边缘元素之和(赛氪OJ)

[题目描述] 输入一个整数矩阵&#xff0c;计算位于矩阵边缘的元素之和。 所谓矩阵边缘的元素&#xff0c;就是第一行和最后一行的元素以及第一列和最后一列的元素。输入&#xff1a; 输入共 m 1 行。 第一行包含两个整数 m, n (1 < m,n < 100) &#xff0c;分别为矩阵的…

力扣双指针算法题目:移动零

1.题目 . - 力扣&#xff08;LeetCode&#xff09; 2.思路解析 这个题目的思路和“使用递归排序快速排序解决数组的排序问题”相同 class solution { public:void QuickSort(vector<int>& nums, int left, int right){if (left > right) return;int key left…

邮件发送失败DKIM报错问题排查解决的方案?

邮件发送DKIM验证失败的排查方法&#xff1f;DKIM的设置步骤&#xff1f; DKIM作为一种验证机制&#xff0c;帮助确保电子邮件的发件人身份验证和邮件内容完整性。然而&#xff0c;发信时可能会遇到DKIM相关的问题&#xff0c;导致邮件发送失败或报错。AokSend将探讨常见的邮件…

电脑端适用何种便签app 精选电脑桌面便签推荐

在数字化时代&#xff0c;电脑已成为我们日常办公不可或缺的工具。在使用电脑办公的同时&#xff0c;我们经常需要随时记录一些重要信息或工作事项。此时&#xff0c;如果能有一款便捷、高效的桌面便签软件&#xff0c;无疑会大大提升我们的工作效率。想象一下&#xff0c;在繁…

SimpleDateFormat 处理带有毫秒的时间字符串转化为时间不准的问题

SimpleDateFormat 处理带有微秒的字符串转化为时间会导致不准确 下面是代码示例&#xff1a; public static void main(String[] args) throws Exception{String timeStampStr "2024-07-04 10:11:34.800017";System.out.println("带毫秒的时间格式: " …

SAP MARA-VPSTA PSTAT 值的意义

参考 https://www.cnblogs.com/VerySky/articles/2851312.html

Stable Diffusion新手快速入门教程,从0到1,AI绘画最基础教程!

关于Ai绘画&#xff0c;很多人在体验了Midjourney&#xff08;以下简称MJ&#xff09;之后&#xff0c;发现它创意能力很强&#xff0c;但可控性比较弱&#xff0c;不便应用&#xff0c;于是转向Stable Diffussion&#xff08;以下简称SD&#xff09;&#xff0c;但又发现SD貌似…

秒懂设计模式--学习笔记(7)【结构型-门面模式】

目录 6、门面模式6.1 介绍6.2 一键操作6.3 亲自下厨的烦扰6.4 化繁为简6.5 整合共享6.6 门面模式的各角色定义 6、门面模式 6.1 介绍 门面模式&#xff08;Facade&#xff09;可能是最简单的结构型设计模式它能将多个不同的子系统接口封装起来&#xff0c;并对外提供统一的高…

2024年用scrapy爬取BOSS直聘的操作

SCrapy框架实现对BOSS直聘的爬取 文章目录 SCrapy框架实现对BOSS直聘的爬取对SCrapy框架的一个简单认识Scrapy 组件的作用Scrapy 数据流 1. 测试反爬2. 定义一个下载中间件类,截取spiders的请求&#xff08;中间件直接截取请求&#xff0c;并且返回给Spider进行数据解析&#x…

文件扫描pdf怎么弄?5个简易高效的文件扫描方法

在繁忙的工作中&#xff0c;我们常常需要将纸质文件快速转换为电子文档&#xff0c;以便于编辑、存储或分享。 无论是合同、报告还是笔记&#xff0c;将这些纸质文件转换为Word格式&#xff0c;不仅能提高工作效率&#xff0c;还能确保信息的安全备份。然而&#xff0c;面对市…

【LLM大模型】中国人工智能大模型技术白皮书,从0入门大模型,附文档+LLM实战教程

近期&#xff0c;中国人工智能学会发布了《中国人工智能大模型技术白皮书》&#xff0c;系统梳理了大模型技术演进&#xff0c;深入探讨关键技术要素&#xff0c;并剖析当前挑战及未来展望。 我为大家做了简要总结&#xff0c;并附上文档分享给大家。 PDF&#xff1a; 完整版本…

Git 操作总结

1. 安装、Git 环境配置 1.1 安装 Git 官方版本可以在 Git 官方网站下载&#xff1a;打开 https://git-scm.com/download/win&#xff0c;选择相应版本即可。 Git 安装完成后&#xff0c;可以在开始菜单中看到 Git 的三个启动图标&#xff08;Git Bash、Git CMD、Git GUI&…

最新mysql打开远程访问和修改最大连接数

这里写目录标题 1.使用navicat进入命令控制板,进入use mysql;2.查询用户表3.更新user表中root用户域属性&#xff0c;%表示允许外部访问4.执行以上语句之后再执行&#xff0c;FLUSH PRIVILEGES;5. 执行授权语句修改最大连接数 1.使用navicat进入命令控制板,进入use mysql; use…

成都百洲文化传媒有限公司电商服务的佼佼者

在当今这个数字化时代&#xff0c;电商已成为商业发展的核心动力之一。成都百洲文化传媒有限公司&#xff0c;作为一家专注于电商服务的领先企业&#xff0c;正以其卓越的服务质量和前瞻性的战略眼光&#xff0c;引领着电商行业的新潮流。 一、公司简介 成都百洲文化传媒有限公…

SF-HCI-SAP问题收集17:值映射布尔型EC数据

Complacency is the enemy of study 学习的敌人是自己的满足。 SAP SuccessFactors Employee Central 到 SAP ERP 的员工主数据复制 successfactor employee center主数据同步&#xff0c;一直以来排错比较难&#xff0c;难的地方是这个提示消息比较隐晦&#xff0c;而且同步的…