【linux进程间通信(一)】匿名管道和命名管道

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:Linux从入门到精通⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学更多操作系统知识
  🔝🔝


在这里插入图片描述

进程间通信

  • 1. 前言
  • 2. 进程间通信的方法
  • 3. 管道的简单介绍
  • 4. 匿名管道
  • 5. 命名管道
  • 6. 总结以及拓展

1. 前言

众所周知,进程运行是具有独立性的,
想要进程间进行通信就要打破这种
独立性,而进程间通信的本质其实是
让不同的进程看见同一份资源!

本章重点:

本篇文章会介绍进程间通信中常见
的几种方式,并且着重讲解匿名管道
和命名管道的这两种通信手段的原理
和代码的实现.


2. 进程间通信的方法

首先通信种类分为三大类:

  • 管道
  • system V
  • POSIX

在这里插入图片描述
当然网络通信的本质其实也是进程
间的通信,但是本篇文章的重点是
利用管道通信!!!


3. 管道的简单介绍

首先要回答什么是管道,在学习
Linux指令时我们使用过竖划线 |
也就是管道,把从一个进程连接
到另一个进程的数据流称为“管道”

在这里插入图片描述

在管道通信中,管道的本质其实就是
一个被系统打开的文件,然而用管道
进行通信的本质就是让不同的进程
看见相同的资源(文件)

并且管道是单向通信的,即一个进程
不能同时从一个管道中读取和写入,
读取和写入要对应两个不同的管道!


4. 匿名管道

在这里插入图片描述

对于匿名管道来说,通常用于父子
进程之间的通信,在父进程使用
pipe创建好管道后,再使用fork创建
子进程,此时子进程会将父进程的
文件描述符表给拷贝过来,也就天然
的拥有这两个管道文件了!

在这里插入图片描述
并且此时我们会面临两个问题:

  1. 读取方将文件关闭了会发送什么?
  2. 读取方在文件中没有数据时会干什么?
  • 读端关闭后,写端进程会终止
  • 当管道无数据时读端会阻塞

有了上面的经验后,现在可以编码验证一下:

int main()
{
    //创建管道
    int pipefd[2]={0}; //0下标表示读取端,1下标表示写入端
    int n = pipe(pipefd);
    assert(n!=-1);
    (void)n;
#ifdef DEBUG//条件编译
    cout<<"[0]: "<<pipefd[0]<<" "<<"[1]: "<<pipefd[1]<<endl;
#endif
    //创建子进程
    pid_t id = fork();
    assert(id!=-1);
    if(id==0)//子进程, 构建单向通信
    {
        close(pipefd[1]);
        char buffer[1024];
        while(1)
        {
            ssize_t s = read(pipefd[0],buffer,sizeof(buffer)-1);
            if(s>0)
            {
                buffer[s]=0;
                cout<<"father# "<<buffer<<endl;
            }
            else//read的返回值等于0代表父进程的管道文件已经close了
            {
                cout<<"写入结束,子进程退出";
                break;
            }
        }
        exit(0);
    }
    //父进程写入,子进程读取
    close(pipefd[0]);
    string str = "我在给子进程发信息";
    int count=0;
    char send_buffer[1024];
    while(count<=5)
    {
        //构建一个变化的字符串
        snprintf(send_buffer, sizeof(send_buffer),"%s[%d]: %d",str.c_str(),getpid(),count++);//往缓冲区里写入数据
        //写入到管道中
        write(pipefd[1],send_buffer,sizeof(send_buffer));
        sleep(1);
    }
    close(pipefd[1]);
    pid_t ret = waitpid(id,NULL,0);
    assert(ret > 0);
    return 0;
}

总结管道的特点:

  • 管道常用于父子进程间的通信
  • 管道是面向字节流的服务
  • 管道是基于文件的,管道的生命周期随进程
  • 管道是单向通信的
  • 写快读慢,写满管道后不能再写了
  • 写慢读快,管道没有数据时,读端要等待
  • 写端关闭,读端会读到0,标识结束
  • 读端关闭,写端继续写会终止进程

5. 命名管道

匿名管道的一个限制就是必须是在
有血缘关系的进程间才能通信,使用
命名管道可以解决这个问题

在这里插入图片描述

匿名管道和命名管道的区别:

  • 匿名管道由pipe函数创建并打开。
  • 命名管道由mkfifo函数创建,打开用open
  • FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的语义。

命名管道的打开规则:

  • 如果当前打开操作是为读而打开FIFO时
  1. O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO
  2. O_NONBLOCK enable:立刻返回成功
  • 如果当前打开操作是为写而打开FIFO时
  1. O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO
  2. O_NONBLOCK enable:立刻返回失败,错误码为ENXIO

命名管道简单通信:

读端代码:

#define SIZE 1024
#define MODE 0666
string ipcpath = "./fifo.ipc";
static void getmessage(int fd)
{
    //编写通信代码
    char buffer[SIZE];
    while(1)
    {
        memset(buffer,'\0',sizeof(buffer));
        ssize_t s = read(fd,buffer,sizeof(buffer)-1);
        if(s>0)//读取成功
        {
            cout<<"["<<getpid()<<"] "<<"client say: "<<buffer<<endl;
        }
        else if(s==0)//写端关闭,并且读到end
        {
            cerr<<"["<<getpid()<<"]"<<"read end"<<endl;
            break;
        }
        else//读取失败
        {
            perror("read");
            break;
        }
    }
}
int main()
{
    //创建管道文件
    int n = mkfifo(ipcpath.c_str(),MODE);
    if(n<0)
    {
        perror("mkfifo");
        exit(1);
    }
    //文件操作
    int fd = open(ipcpath.c_str(),O_RDONLY);//这里必须等待client进程将此管道文件打开后才能执行下面的代码
    if(fd<0)
    {
        perror("open");
        exit(2);
    }
    for(int i=0;i<4;i++)
    {
        int id = fork();
        if(id==0)
        {
            getmessage(fd);
            exit(0);
        }
    }
    
    close(fd);
    return 0;
}

写端代码:

#define SIZE 1024
#define MODE 0666
string ipcpath = "./fifo.ipc";
int main()
{
    //client不用自己创建管道文件,只需获取文件即可
    int fd = open(ipcpath.c_str(),O_WRONLY);
    if(fd<0)
    {
        perror("open");
        exit(1);
    }
    //通信过程
    string buffer;
    while(1)
    {
        cout<<"please Enter message: ";
        getline(cin,buffer);
        write(fd,buffer.c_str(),buffer.size());
    }
    close(fd);
    return 0;
}

6. 总结以及拓展

虽然匿名管道和命名管道已经包含了
对于有血缘关系和无血缘关系的进程
的通信,但是毕竟调用read和write这些
系统调用接口会不断的在用户态和内核
态进行切换,比较消耗资源,所以管道不是
最好的!

拓展: 为什么读端关闭后,写端进程会终止?

这是因为当读端关闭后,写端再使用
write操作会产生SIGPIPE信号,此进
程收到此信号进而会终止进程,可以
使用捕捉信号的方式验证这一结论


🔎 下期预告:共享内存通信方式 🔍

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

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

相关文章

计算机毕业设计 基于SpringBoot的红色革命文物征集管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

CSS 实现卡片以及鼠标移入特效

CSS 实现卡片以及鼠标移入特效 文章目录 CSS 实现卡片以及鼠标移入特效0、效果预览默认鼠标移入后 1、创建卡片组件2、添加样式3、完整代码 0、效果预览 默认 鼠标移入后 在本篇博客中&#xff0c;我们将探讨如何使用 CSS 来实现卡片组件&#xff0c;并添加鼠标移入特效&#…

第五回 九纹龙剪径赤松林 鲁智深火烧瓦罐寺 Webmin傻瓜式配置服务器

话说鲁智深走过数个山坡&#xff0c;看见一所败落的寺庙&#xff0c;上写“瓦罐之寺”。庙里空无一人&#xff0c;于是鲁智深径直走到后面厨房&#xff0c;发现有几个老和尚。鲁智深向和尚们讨要饭食&#xff0c;和尚们初时推说没有。然而&#xff0c;鲁智深眼尖&#xff0c;发…

【Python程序开发系列】一文搞懂argparse模块的常见用法(案例+源码)

一、引言 argsparse是python的命令行解析的标准模块&#xff0c;内置于python&#xff0c;不需要安装。这个库可以让我们直接在命令行中就可以向程序中传入参数并让程序运行。 在运行深度学习程序时。往往会因为电脑配置不行导致程序运行慢卡&#xff0c;需要将程序在虚机上进行…

【React基础】– JSX语法

文章目录 认识JSX为什么React选择了JSXJSX的使用 React事件绑定this的绑定问题事件参数传递 React条件渲染React列表渲染列表中的key JSX的本质createElement源码Babel官网查看直接编写jsx代码 虚拟DOM的创建过程jsx – 虚拟DOM – 真实DOM声明式编程 阶段案例练习 认识JSX ◼ …

手动添加测试用例配置输入参数和期望值

1.选中函数&#xff0c;点击右键选择插入测试用例。这里所选择的插入测试用例区别于之前的测试用例的地方在于&#xff0c;这里插入测试用例是手动配置的&#xff0c;之前的是自动生成的。手动配置可以自定义选择输入参数和期望值。 2.添加测试用例后&#xff0c;点击测试用例&…

高光谱分类论文解读分享之Grid Network: 基于各向异性视角下特征提取的高光谱影像分类

IEEE GRSL 2023&#xff1a;Grid Network: 基于各向异性视角下特征提取的高光谱影像分类 题目 Grid Network: Feature Extraction in Anisotropic Perspective for Hyperspectral Image Classification 作者 Zhonghao Chen , Student Member, IEEE, Danfeng Hong , Senior …

Conmi的正确答案——使用eclipse进行ESP32C3的debug

eclipse IDE 版本:2023-12 1、安装debug环境 参考大神的教程:【图文】手把手教你使用 Eclipse IDE 开发 ESP32 (这里是为了我下次回来速通才写的部分) 1.1、安装插件(plug-in,新的软件已经写成software了): 相关软件参数: 汉化(安装完成会提示重启应用): Name:…

【前后端的那些事】15min快速实现图片上传,预览功能(ElementPlus+Springboot)

文章目录 Element Plus SpringBoot实现图片上传&#xff0c;预览&#xff0c;删除效果展示 1. 后端代码1.1 controller1.2 service 2. 前端代码2.1 路由创建2.2 api接口2.2 文件创建 3. 前端上传组件封装 前言&#xff1a;最近写项目&#xff0c;发现了一些很有意思的功能&…

node.js 实现文件上传 和图片映射 文件下载(multer)

Muter是一个node.js中间件。主要处理multupart/from-data类型的表单数据&#xff0c;常用于上传文件。在express.js应用中&#xff0c;multer使得上传文件变得更加简单。主要功能是将客户端上传的文件存储在服务器的本地文件系统中。它还添加了一个body对象以及file或files对象…

qnx 上screen + egl + opengles 最简实例

文章目录 前言一、qnx 上的窗口系统——screen二、screen + egl + opengles 最简实例1.使用 addvariant 命令创建工程目录2. 添加源码文件3. common.mk 文件4. 编译与执行总结参考资料前言 本文主要介绍如何在QNX 系统上使用egl和opengles 控制GPU渲染一个三角形并显示到屏幕上…

数据结构与算法-二叉树-从前序与中序遍历序列构造二叉树

从前序与中序遍历序列构造二叉树 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 示例 1: 输入: preorder [3,9,20,15,7], inorder [9,3,15,20,7…

Ubuntu18.04在线镜像仓库配置

在线镜像仓库 1、查操作系统版本 rootubuntu:~# lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 18.04.5 LTS Release: 18.04 Codename: bionic 2、原文件备份 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak 3、查…

深入理解Linux文件系统

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;晴る—ヨルシカ 0:20━━━━━━️&#x1f49f;──────── 4:30 &#x1f504; ◀️ ⏸ ▶️ ☰ &…

宋仕强论道之华强北的领军企业(四十六)

华强北曾经的3发展是因为领军企业的带动而蓬勃发展&#xff0c;当年的华强集团、赛格集团、桑达集团和华发集团等是其中的代表&#xff0c;但现在他们失去了曾经的带头大哥的地位。其他的例子&#xff0c;如腾讯对于深圳市南山区科技园的带动&#xff0c;华为对龙岗坂田雪象岗头…

MySQL面试题 | 16.精选MySQL面试题

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

Leetcode2207. 字符串中最多数目的子字符串

Every day a Leetcode 题目来源&#xff1a;2207. 字符串中最多数目的子字符串 解法1&#xff1a;贪心 一次遍历 设 pattern 的第一个字符为 x&#xff0c;第二个字符为 y。 根据题意&#xff0c;x 插入的位置越靠左&#xff0c;答案的个数越多&#xff1b;y 插入的位置越…

C#: form 窗体的各种操作

说明&#xff1a;记录 C# form 窗体的各种操作 1. C# form 窗体居中显示 // 获取屏幕的宽度和高度 int screenWidth Screen.PrimaryScreen.Bounds.Width; int screenHeight Screen.PrimaryScreen.Bounds.Height;// 设置窗体的位置 this.StartPosition FormStartPosition.M…

【Android】自定义View onDraw()方法会调用两次

问题 自定义了View后&#xff0c;在构造函数中设置画笔颜色&#xff0c;发现它没起效&#xff0c;但是在onDraw()里设置颜色就会起效&#xff0c;出问题的代码如下&#xff1a; public RoundSeekbarView(Context context, Nullable AttributeSet attrs) {super(context, attrs…

Discuz论坛网站登录账号操作慢,必须强制刷新才会显示登录怎么办?

飞飞发现在登录服务器大本营账号时&#xff0c;输入账号密码登录后还是显示的登录框&#xff0c;强制刷新后才知道已经登录了&#xff0c;每次都要刷新才能正常显示&#xff0c;非常影响用户体验&#xff0c;于是在网上找了类似的问题故障解决方法&#xff0c;目前问题已经解决…