Linux进程间通讯 -- 管道

Linux进程间通讯 – 管道

文章目录

  • Linux进程间通讯 -- 管道
    • 1. 原理
    • 2. 进程间通讯
      • 2.1 管道
        • 2.1.1 匿名管道 `pipe`
        • 2.2.2 有名管道 `FIFO`
      • 2.2 信号
      • 2.3 共享内存
      • 2.4 本地套接字

1. 原理

Linux 进程间通讯,也称为IPC(InterProcess Communication)

在 Linux 中每个进程都具备独立的进程地址空间,对每个进程的独立地址空间进行划分,在0G - 3G部分被划分为用户空间,而3G - 4G部分被划分为内核地址空间。注意此0G - 4G 为虚拟地址空间,实际上会通过MMU映射到物理地址空间。

在进行地址映射的时候,每个进程的用户空间在实际物理空间上将被映射到多个地址空间,而多个进程的内核空间将会被被映射到同一块区域,因此多个进程之间具备相同的内核地址空间,通过此共同的内核地址空间实现线程间数据交互即为进程间通讯,也即IPC。
在这里插入图片描述

2. 进程间通讯

Linux进程间通讯的方式主要分为以下四大种类型:

  1. 管道 pipe
  2. 信号 signal
  3. 共享映射区 mmap
  4. 本地套接字 socket

2.1 管道

使用管道实现进程间通讯的优点是:使用简单!

管道分为有名管道 FIFO 和匿名管道 pipe,匿名管道仅能用于具备血缘关系的进程间通讯;而有名管道因其具备了名字可以被找到,因此可用于无血缘关系的进程间通讯。

管道本质是一个伪文件,是由内核管理的一个缓冲区,同时此缓冲区被设计成环形,具备两个端口,一端连接数据的写入,一端连接数据的输出,因此管道仅可用于单向通讯的场合

当管道中无有效数据时,从管道中读取数据时进入阻塞等待状态,直至有数据从管道的写端写入。

当管道中数据被写满时,再次往管道内写入数据会进入阻塞等待状态,直至有数据从管道的读端被读走。

2.1.1 匿名管道 pipe

创建管道:

#include <unistd.h>

int pipe(int pipefd[2]);
  • 传入参数:包含两个文件指针的数组,pipefd[0] 指向管道的读端;pipefd[1] 指向管道的写端
  • 返回值:0:成功 -1:失败

示例:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>

int main(int argc, char **argv)
{
    int fd[2] = { 0 };
    int ret = 0;
    pid_t pid = 0;
    char buf[512] = {0};

    ret = pipe(fd);
    if (ret < 0) {
        perror("create pipe failed");
        return -1;
    }

    pid = fork();
    if (pid == 0) {
        printf("----------Is child process ------------\n");
        close(fd[0]);       /* close the read of pipe. */
        write(fd[1], "hello world!\n", sizeof("hello world!\n"));
    } else {
        if (pid < 0) {
            perror("fork failed");
            return -1;
        }
        printf("----------Is father process -----------\n");
        close(fd[1]);       /* close the write of pipe. */

        while (1) {
            memset(buf, 0, sizeof(buf));
            ret = read(fd[0], buf, sizeof(buf));
            printf("ret:%d read:%s\n", ret, buf);
            sleep(1);
        }
    }

    return 0;
}

运行结果如下:
在这里插入图片描述
运行分析:

  1. 使用pipe创建一个匿名管道
  2. 使用fork创建子进程,父子进程均拥有此pipe
  3. 子进程关闭管道读端,延时1s后往管道写端写入数据
  4. 父进程关闭管道写端,之后马上对管道读端读取数据,此时由于管道内没有有效数据,因此父进程发生阻塞,直至子线程往管道内写入数据
  5. 子进程写完数据后进程结束,对应的写端口被系统关闭,因此父进程读取管道直接返回0,不再阻塞。
    在这里插入图片描述
2.2.2 有名管道 FIFO

创建有名管道:

#include <sys/types.h>
#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);
  • 传入参数:
    • pathname: 有名管道名字
    • mode: 有名管道对应文件的权限(8进制),最终文件权限为 (mode & ~umask),通常此值使用0664
  • 返回值:
    • 0: success -1:fail

注意事项:

  1. 如果存在有名管道对应名字的文件,则会返回错误 errno = EEXIST,因此没有做特殊处理时,重复运行此程序通常会报错。

  2. 创建好了有名管道之后,open此有名管道时,必须要求此管道的读端和写端均被打开,否则 open 函数会进入阻塞状态

    • 如果采用只读模式 open("test_fifo", O_RDONLY)打开,则open函数会阻塞直至其他函数采用O_WRONLYO_RDWR打开写端
    • 如果采用只写模式 open("test_fifo", O_WRONLY)打开,则open函数会阻塞直至其他函数采用O_RDONLYO_RDWR打开读端
    • 如果采用非阻塞方式打开只读端口 open("test_fifo", O_RDONLY | O_NONBLOCK) 不会报错,但采用非阻塞方式打开只写接口 open("test_fifo", O_WRONLY | O_NONBLOCK) 会返回 No such device or address 错误
    • 因此采用读写方式打开不会发送阻塞也不会报错 open("test_fifo", O_RDWR),但应用不一定安全!

示例:

fifo_r.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char **argv)
{
    int fd = 0, ret = 0;
    char buf[512] = {0};

    if (mkfifo("test_fifo", 0664) < 0 && errno != EEXIST) {
        perror("mkfifo error");
        return -1;
    }

    //fd = open("test_fifo", O_RDONLY | O_NONBLOCK);
    fd = open("test_fifo", O_RDONLY );
    if (fd < 0) {
        perror("open fifo error");
        return -1;
    }

    while (1) {
        ret = read(fd, buf, sizeof(buf));
        printf("read: ret:%d, buf = %s\n", ret, buf);
        sleep(1);
    }
    
    return 0;
}

fifo_w.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

int main(int argc, char **argv)
{
    int fd = 0, ret = 0;
    int cnt = 0;
    char buf[512] = {0};

    if (mkfifo("test_fifo", 0664) < 0 && errno != EEXIST) {
        perror("mkfifo error");
        return -1;
    }

    //fd = open("test_fifo", O_RDWR);
    fd = open("test_fifo", O_WRONLY);
    if (fd < 0) {
        perror("open fifo error");
        return -1;
    }

    while (1) {
        cnt ++;
        snprintf(buf, sizeof(buf), "hello world! cnt:%d", cnt);

        ret = write(fd, buf, strlen(buf)+1);
        printf("write: ret:%d, buf = %s\n", ret, buf);
        sleep(2);
    }
    
    return 0;
}

运行结果:
在这里插入图片描述
对应创建的test_fifo文件如下
在这里插入图片描述

2.2 信号

//TODO:

2.3 共享内存

//TODO:

2.4 本地套接字

//TODO:

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

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

相关文章

Doris初识(01)

Doris初识 初识 Apache Doris 是一个基于 MPP 架构的高性能、实时的分析型数据库&#xff0c;以极速易用的特点被人们所熟知&#xff0c;仅需亚秒级响应时间即可返回海量数据下的查询结果&#xff0c;不仅可以支持高并发的点查询场景&#xff0c;也能支持高吞吐的复杂分析场景…

嵌入式培训机构四个月实训课程笔记(完整版)-Linux系统编程第三天-Linux进程(物联技术666)

更多配套资料CSDN地址:点赞+关注,功德无量。更多配套资料,欢迎私信。 物联技术666_嵌入式C语言开发,嵌入式硬件,嵌入式培训笔记-CSDN博客物联技术666擅长嵌入式C语言开发,嵌入式硬件,嵌入式培训笔记,等方面的知识,物联技术666关注机器学习,arm开发,物联网,嵌入式硬件,单片机…

H266/VVC网络适配层概述

视频编码标准的分层结构 视频数据分层的必要性&#xff1a;网络类型的多样性、不同的应用场景对视频有不同的需求。 编码标准的分层结构&#xff1a;为了适应不同网络和应用需求&#xff0c;视频编码数据根据其内容特性被分成若干NAL单元&#xff08;NAL Unit&#xff0c;NALU…

WEB 3D技术 three.js 顶点旋转

我们来说说几何体顶点的旋转 官网搜索 BufferGeometry 这里 我们有 x y z 三个轴的旋转 例如 我们这样的代码 import ./style.css import * as THREE from "three"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; i…

第二十七周:文献阅读笔记

第二十七周&#xff1a;文献阅读笔记 摘要AbstractDenseNet 网络1. 文献摘要2. 引言3. ResNets4. Dense Block5. Pooling layers6. Implementation Details7. Experiments8. Feature Reuse9. 代码实现 总结 摘要 DenseNet&#xff08;密集连接网络&#xff09;是一种深度学习神…

AI 工具探索(二)

我参加了 奇想星球 与 Datawhale 举办的 【AI办公 X 财务】第一期&#xff0c;现在这是第二次打卡&#xff0c;也即自由探索&#xff0c;我选择 Modelscope 的 Agent 探索&#xff0c;并用gpts创作助理对比&#xff01; 最近想学学小红书的运营方法&#xff0c;选择了 小红书I…

图像分割-Grabcut法

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 本文的C#版本请访问&#xff1a;图像分割-Grabcut法(C#)-CSDN博客 GrabCut是一种基于图像分割的技术&#xff0c;它可以用于将图像…

CnosDB容灾方案概述

本文主要介绍了跟容灾相关的关键技术以及技术整合后形成的几种具体方案&#xff0c;每种方案都在RTO、RPO、部署成本和维护成本等方面有自己的特点和区别&#xff0c;可以根据具体场景选择最合适的方案。 基本概念 RTO&#xff08;Recovery Time Objective&#xff09;&#x…

Qt基本认识

1. 基本认识 1.1 学习方法&#xff1a; &#xff08;1&#xff09;英语阅读能力要好一点 QT将一些类和方法进行了封装&#xff0c;一般是采用英语&#xff08;方法名、属性、子类、父类等等&#xff09;进行介绍 &#xff08;2&#xff09;学习QT reator 1&#xff09;多查帮助…

数据交互系列:认识 cookie

cookie的原理 http本身是一个无状态的请求&#xff0c;cookie最初的原始目的是为了维持状态而产生的。在首次访问网站时&#xff0c;浏览发送请求中并未携带cookie&#xff0c;即发送无状态请求服务器接受请求之后会在请求上的respond header上加入cookie相关信息并返回给浏览…

数字孪生在虚拟现实(VR)中的应用

数字孪生在虚拟现实&#xff08;VR&#xff09;中的应用为用户提供了更深入、沉浸式的体验&#xff0c;同时通过数字孪生技术模拟真实世界的物理实体。以下是数字孪生在VR中的一些应用&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发…

13年测试老鸟,性能测试-全链路压测总结,一文打通...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、什么是全链路压…

二维和三维联合进行圆孔空间定位

0.任务描述 对空间圆孔进行三维空间的定位&#xff0c;方便后续的抓取或装配流程&#xff1a;使用二维图与opencv霍夫圆检测进行二维上的定位&#xff0c;再从深度图上查询深度信息&#xff0c;结合相机内参计算出相机坐标系下圆孔的三维坐标信息&#xff0c;并在点云上进行标…

自定义View之重写onMeasure

一、重写onMeasure()来修改已有的View的尺寸 步骤&#xff1a; 重写 onMeasure()&#xff0c;并调用 super.onMeasure() 触发原先的测量用 getMeasuredWidth() 和 getMeasuredHeight() 取到之前测得的尺寸&#xff0c;利用这两个尺寸来计算出最终尺寸使用 setMeasuredDimensio…

[通俗易懂]c语言中指针变量和数值之间的关系

一、指针变量的定义 在C语言中&#xff0c;指针变量是一种特殊类型的变量&#xff0c;它存储的是另一个变量的内存地址。指针变量可以用来间接访问和操作内存中的其他变量。指针变量的定义如下&#xff1a; 数据类型 *指针变量名&#xff1b;其中&#xff0c;数据类型可以是任…

SQL优化:执行计划

前面我们讲述了使用索引或分区表来进行存储层次的优化,也讲述了通过条件提升进行结果集的优化。这边文章我们来学习一下其中的细节,即查看数据库是怎么一步一步把数据拿给我们的。也就是执行计划。 语法 explain sql语句 练习 首先,我们来玩下简单的 explain select * …

HUAWEI WATCH 系列 eSIM 全新开通指南来了

HUAWEI WATCH 系列手表提供了eSIM硬件能力&#xff0c;致力为用户提供更便捷、高效的通信体验。但eSIM 业务是由运营商管理并提供服务的&#xff0c;当前运营商eSIM业务集中全面恢复&#xff0c;电信已经全面恢复&#xff0c;移动大部分省份已经全面放开和多号App开通方式&…

20240107移远的4G模块EC20在Firefly的AIO-3399J开发板的Android11下调通能上网

20240107移远的4G模块EC20在Firefly的AIO-3399J开发板的Android11下调通能上网 2024/1/7 11:17 开发板&#xff1a;Firefly的AIO-3399J【RK3399】SDK&#xff1a;rk3399-android-11-r20211216.tar.xz【Android11】 Android11.0.tar.bz2.aa【ToyBrick】 Android11.0.tar.bz2.ab …

Docker mysql 主从复制

目录 介绍&#xff1a;为什么需要进行mysql的主从复制 主从复制原理&#xff1a; ✨主从环境搭建 主从一般面试问题&#xff1a; 介绍&#xff1a;为什么需要进行mysql的主从复制 在实际的生产中&#xff0c;为了解决Mysql的单点故障已经提高MySQL的整体服务性能&#xff…

如何恢复Mac误删文件?

方法1. 使用撤消命令 当你在 Mac 上删除了错误的文件并立即注意到你的错误时&#xff0c;你可以使用撤消命令立即恢复它。顾名思义&#xff0c;此命令会反转上次完成的操作&#xff0c;并且有多种方法可以调用它。如果你已经采取了其他操作或退出了用于删除文件的应用程序&…