【Linux】进程间通信之管道(pipe)

news2024/11/16 19:34:34

文章目录

  • 前言
  • 为什么要进程间通信
  • 进程间通信的理论依据
  • 管道
  • 管道的原理
  • 创建匿名管道
  • 管道的特点
  • 管道的场景
  • 利用管道控制子进程
  • 命名管道
  • 命名管道的打开规则
  • 命名管道和匿名管道的区别
  • 用命名管道实现server和client通信

前言

大家好久不见,今天开始我们将进入进程间通信章节的学习。

为什么要进程间通信

现在看来,无非是为了资源共享。

进程间通信的理论依据

我们知道进程是独立的,如果我们要进行通信,前提是让两个进程能看到同一份资源。

管道

管道是unix中古老的通信方式,通过管道,我们可以完成进程间通信。
我们把从一个进程连接到另一个进程的数据流称之为管道。

管道的原理

父进程fork的时候,子进程会继承父进程打开的文件描述符,利用这个特性,设计出管道来完成进程间通信。
在这里插入图片描述
即让父进程创建管道,并fork创建子进程,再关闭对应写/读端

创建匿名管道

#include <unistd.h>

int pipe(int fd[2]);
功能:创建匿名管道
参数:fd,文件描述符数组,输出型参数,fd[0]读,fd[1]写
返回值:成功返回0,失败返回错误代码

管道的演示代码:

#include <iostream>
#include <string>
#include <cerrno>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <unistd.h>

using namespace std;

int main()
{
    //1.创建管道
    int pipeid[2];
    int n = pipe(pipeid);
    if(n < 0)
    {
        cout << errno << strerror(errno) << endl;
    }
    cout << pipeid[0] << endl; //0是张嘴 就是读
    cout << pipeid[1] << endl; //1是个笔 就是写
    //2.创建子进程
    pid_t id = fork();
    assert(id != -1);
    if(id == 0)
    {
        //3.关闭不需要的fd,父进程读取,子进程写
        close(pipeid[0]);

        //5.通信开始
        const string namestr = "hello,i am child";
        int cnt = 1;
        char buffer[1024];
        while(true)
        {
            snprintf(buffer,sizeof(buffer),"%s,my cnt = %d,myPID = %d\n",namestr.c_str(),cnt++,getpid());
            write(pipeid[1],buffer,strlen(buffer));
            sleep(1);
        }

        close(pipeid[1]);
        //让下面的代码被父进程独享
        exit(0);
    }

    //4.父进程关闭写
    close(pipeid[1]);
    

    //5.开始父子进程通信:要结合某种场景!!!!
    char buffer[1024];
    while(true)
    {
        int n = read(pipeid[0],buffer,sizeof(buffer)-1);
        //这里-1是给 \0 留位置
        cout << "没有被阻塞住" << endl;

        //cout << n << endl;
        if(n > 0)
        {
            buffer[n] = '\0';
            cout << "child send me message:" << buffer << endl;
        }
    }

    return 0;
}

管道的特点

1、单向通信,管道是半双工的特殊情况。半双工即上课模式,老师讲完,学生问问题。
2、管道本质是文件,有对应的文件描述符fd,因此管道的生命周期随进程。
3、管道通信通常在有血缘关系的进程间通信,如父子进程。
4、管道通信写入和读取次数不是严格匹配的,两者没有强相关。原因在于 字节流
5、具有一定协同能力,让读和写能按照一定步骤进行通信。自带同步机制

管道的场景

1、如果read读取了所有的管道数据,对方不发,只能等待
2、管道写满后不可以再写,因为管道是有大小的
3、如果write关闭,读完管道数据,再读就会返回0,表明读到文件的结尾
4、写端一直写,读端关闭,OS会杀死一直写入却不读的进程,13)SIGPIPE

利用管道控制子进程

管道不只可以用来进程间通信,也可以利用管道控制子进程,比如父进程发送指令使得子进程退出。

命名管道

上述由继承得到的管道关系被称为匿名管道,匿名管道只能在具有亲缘关系的进程间进行通信,假如我们想让两个毫不相关的进程通信,可以使用命名管道。

1、在命令行上创建一个管道
mkfifo [filename]

2、函数调用
int mkfifo(const char* filename, mode_t mode)
参数:filename文件名,mode是开启管道的权限
返回值:调用成功返回0,调用失败返回-1

3、删除一个管道
unlink [filename]

命名管道的打开规则

  • 如果当前操作为读
    • 阻塞直到有相应进程写操作打开FIFO
    • 若设置O_NONBLOCK,立即返回成功
  • 如果当前操作为写
    • 阻塞直到有相应进程读操作打开FIFO
    • 若设置O_NONBLOCK,立即返回失败

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

1、命名管道由mkfifo创建,open开启。
2、匿名管道由pipe打开。

用命名管道实现server和client通信

server.cc

#include <iostream>
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include "comm.hpp"

int main()
{
    //1、创建管道文件
    umask(0);
    int n = mkfifo(fifoname.c_str(),mode);
    if(n != 0)
    {
        std::cout << errno << ":" << strerror(errno) << std::endl;
        return -1;
    }

    std::cout << "管道创建完成" << std::endl;

    //2、服务端开启管道文件
    int r_fd = open(fifoname.c_str(),O_RDONLY);
    if(r_fd < 0)
    {
        std::cout << errno << ":" << strerror(errno) << std::endl;
        return -2;
    }
    std::cout << "管道文件已经成功开启,等待通信" << std::endl;
    
    //3、正常进行通信:
    char buffer[NUM];
    while(true)
    {
        buffer[0] = '\0';
        ssize_t n = read(r_fd,buffer,sizeof(buffer));
        //系统调用都不去管C语言字符串的规定
        //std::cout << n << std::endl;
        if(n > 0)
        {
            buffer[n] = 0;
            std::cout << "clien:" << buffer << std::endl;
        }
        else if(n == 0)
        {
            std::cout << "client quit, me quit too!" << std::endl;
            break;
        }
        else 
        {
            std::cout << errno << ":" << strerror(errno) << std::endl;
            break;
        }
    }

    // 关闭
    close(r_fd);
    unlink(fifoname.c_str());

    return 0;
}

client.cc

#include <iostream>
#include <cstdio>
#include <cerrno>
#include <cstring>
#include <cassert>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include "comm.hpp"

int main()
{
    //以写方式打开管道
    int w_fd = open(fifoname.c_str(),O_WRONLY);
    if(w_fd < 0)
    {
        std::cout << errno << ":" << strerror(errno) << std::endl;
    }

    //进行通信
    char buffer[NUM];
    while(true)
    {
        std::cout << "请输入消息#";
        
        char* msg = fgets(buffer,sizeof(buffer),stdin);
        assert(msg);(void)msg;
        
        //1 2 3 4 5 /n/0
        //0 1 2 3 4 5 /0
        buffer[strlen(buffer)-1] = 0;
        if(strcasecmp(buffer,"quit") == 0) break;
        ssize_t n = write(w_fd,buffer,sizeof(buffer)-1);
    }
    return 0;
}

运行即可达到如下效果:
在这里插入图片描述

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

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

相关文章

redis高可用方案:主从复制+哨兵模式,经典案例:一主二从三哨兵,及springboot集成配置

Redis高可用方案&#xff1a;主从复制哨兵模式 经典案例&#xff1a;一主二从三哨兵&#xff0c;及springboot集成配置 第一.配置 1.主节点配置&#xff08;redis.conf&#xff09; # 主节点配置 仅展示必要配置 redis.conf # 保护模式设置为关&#xff0c;方便其他节点访问…

推荐几款炫酷的 MySQL 可视化管理工具!好用到爆!!

MySQL 的管理维护工具非常多&#xff0c;除了系统自带的命令行管理工具之外&#xff0c;还有许多其他的图形化管理工具&#xff0c;工具好用是一方面&#xff0c;个人的使用习惯也很重要&#xff0c;这里介绍 13 款 MySQL 图形化管理工具&#xff0c;供大家参考。 1&#xff1a…

vite .env.test环境使用ant design vue ,打包后a-date-picker控件无法选择日期

前端开发后台管理系统&#xff0c;常用的UI库当属Element UI和 Ant Design Vue&#xff0c;但是前段时间遇到一个奇葩问题&#xff0c;在这里记录一下&#xff0c;防止小伙伴们踩坑。 后台系统&#xff0c;大家肯定都用过时间控件&#xff0c;本期我们使用的是ant design vue&…

2道关于chan的面试题

题目一: 下面关于通道描述正确的是: 1.读nil chan会触发panic 2.写nil chan会触发panic 3.读关闭的chan会触发panic 4.写关闭的chan会触发panic解答&#xff1a;这个提涉及到2个知识点&#xff0c;操作nil的chan会怎么样&#xff0c;操作关闭的chan会怎么样&#xff0c;下面我…

双目相机测距原理

双目相机测距是一种常用的计算机视觉技术&#xff0c;它利用两个摄像头同时拍摄同一场景&#xff0c;通过测量两个摄像头视野中同一物体在图像上的像素差异&#xff0c;从而计算出物体距离的方法。 具体原理如下&#xff1a; 双目相机的构成 双目相机由两个摄像头组成&#…

用ChatGPT怎么赚钱?普通人用这5个方法也能赚到生活费

ChatGPT在互联网火得一塌糊涂&#xff0c;因为它可以帮很多人解决问题。比如&#xff1a;帮编辑人员写文章&#xff0c;还可以替代程序员写代码&#xff0c;帮策划人员写文案策划等等。ChatGPT这么厉害&#xff0c;能否用它来赚钱呢&#xff1f;今天和大家分享用ChatGPT赚钱的5…

Cesium关于3Dtiles的细节分享

介绍 介绍一下Cesium中有关3dTiles的奇淫技巧&#xff0c;存在一些埋坑的地方&#xff0c;以下内容仅为自己摸索的细节和方法&#xff0c;仅供参考&#xff0c;若有更好的办法欢迎讨论 通用快速获取feature中包含的属性信息 有时候需要快速获得3dTiles中的feature中的属性信…

deb文件如何安装到iphone方法分享

Cydia或同类APT管理软件在线安装 Cydia或同类APT管理软件在线安装,这个是最佳的安装方式,因为通常无需考虑依赖关系,但缺点是对网络的要求比较高;命令行中以dpkg-iXXX.deb的形式安装,好处是可以以通配符一次性安装多个deb,而且也可以直接看到脚本的运行状况和安装成功/失…

执行命令行程序测试自动化

这几天有一个小工具需要做测试&#xff0c;是一个命令行工具&#xff0c;这个命令行工具有点类似mdbg等命令行工具&#xff0c;即程序运行后&#xff0c;在命令行等待用户敲入的命令&#xff0c;处理命令并显示结果&#xff0c;再继续等待用户敲入新的命令。 原来的测试用例都…

Vue实现自动化平台(五)--用例编辑页面

上一章&#xff1a;Vue实现自动化平台&#xff08;四&#xff09;--接口管理页面的实现_做测试的喵酱的博客-CSDN博客 github地址&#xff1a;https://github.com/18713341733/vuemiaotest 这个目前只是用来练手的&#xff0c;项目还没成型。等以后我写完了&#xff0c;再更…

公网远程访问局域网SQL Server数据库【无公网IP内网穿透】

目录 1.前言 2.本地安装和设置SQL Server 2.1 SQL Server下载 2.2 SQL Server本地连接测试 2.3 Cpolar内网穿透的下载和安装 2.3 Cpolar内网穿透的注册 3.本地网页发布 3.1 Cpolar云端设置 3.2 Cpolar本地设置 4.公网访问测试 5.结语 转发自CSDN远程穿透的文章&…

不用但一定要懂 ---- iOS 之 响应链、传递链 与 手势识别

iOS 事件的主要由&#xff1a;响应连 和 传递链 构成。一般事件先通过传递链&#xff0c;传递下去。响应链&#xff0c;如果上层不能响应&#xff0c;那么一层一层通过响应链找到能响应的UIResponse。 响应链&#xff1a;由最基础的view向系统传递&#xff0c;first view ->…

c/c++:原码,反码,补码和常见的数据类型取值范围,溢出

c/c&#xff1a;原码&#xff0c;反码&#xff0c;补码和常见的数据类型取值范围&#xff0c;溢出 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;此时学会c的话&#xff0c; 我所知道的周边的会c的同学&#xff0c;可手握…

前脚我的 GPT4 被封,后脚收到了文心一言的邀请账号

大家好&#xff0c;我是二哥呀。 一早醒来&#xff0c;我的 ChatGPT Plus 账号就惨遭封禁&#xff0c;很不幸&#xff0c;我刚冲的 Plus 会员&#xff0c;用了不到一周的时间&#xff08;&#x1f62d;&#xff09;。 我没用亚洲的IP&#xff0c;所以网上传的那些不使用亚洲IP…

vuex中的 mapState, mapMutations

vuex中的 mapState&#xff0c; mapMutations Start 今天使用vuex的过程中&#xff0c;遇到 mapState&#xff0c; mapMutations 这么两个函数&#xff0c;今天学习一下这两个函数。 本文介绍的vuex基于 vuex3.0 1. 官方文档说明 1.1 mapState 官方解释 点击这里&#xff1…

深入理解IP地址

我们在浏览器中直接输入IP地址就可以访问某一个神秘的网站&#xff0c;那么这个IP地址是如何划分的呢&#xff1f; IP&#xff0c;英文全写为Internet Protocol&#xff0c;指TCP/IP网络体系中的网际互联协议&#xff0c;工作在OSI模型的网络层(简单了解即可)。 更多内容欢迎访…

数据分析之Matplotilb数据可视化

文章目录1.Matplotilb 基础plt.show()函数plt.plot()函数基本用法例子坐标轴显示的范围传入Numpy数组传入多组数据线条属性使用plt.plot()的返回值来设置线条属性plt.setp()修改线条性质子图plt. subplot (numrows, numcols,fignum)形式3.电影数据绘图(1)绘制每个国家或地区的电…

Python的输入与输出

✅作者简介&#xff1a;CSDN内容合伙人、阿里云专家博主、51CTO专家博主、新星计划第三季python赛道Top1&#x1f3c6; &#x1f4c3;个人主页&#xff1a;hacker707的csdn博客 &#x1f525;系列专栏&#xff1a;零基础入门篇 &#x1f4ac;个人格言&#xff1a;不断的翻越一座…

力扣-刷题记录

189. 轮转数组 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 力扣https://leetcode.cn/problems/rotate-array/description/ void rotate(int* nums, int numsSize, int k){if(k > numsSize){k % numsSize;}if(k0){f…

GlusterFS(GFS)分布式文件系统

目录 一.文件系统简介 1.文件系统的组成 2.文件系统的作用 3.文件系统的挂载使用 二.GlusterFS概述 1.GlusterFS是什么&#xff1f; 2.GlusterFS的特点 3.GlusterFS术语介绍 3.1 Brick&#xff08;存储块&#xff09; 3.2 Volume&#xff08;逻辑卷&#xff09; 3.3…