Linux管道

2023-05-16

目录

1.管道概念

2.管道分类

        1.匿名管道

        1.基本实现与概念

        2.站在文件描述符角度-深度理解管道

        3.站在内核角度-管道本质

        4.管道读写规则

        5.管道属性设置与阻塞验证       

         6.管道特点(匿名)

        2.命名管道

        1.创建一个命名管道

        2.命名管道的打开规则 

 3.匿名管道与命名管道的区别


1.管道概念

        管道是Linux中的最古老的通信方式;

        我们把一个进程链接到另一个进程的一个数据流称为一个"管道";

2.管道分类

        1.匿名管道

        1.基本实现与概念

        头文件: #include <unistd.h>

        功能:创建一无名管道原型int pipe(int fd[2]);

        参数fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端返回值:成功返回0,失败返回错误代码

         通常用fork函数来共享管道;接下来我们来实现一下匿名管道的基本读写的实现:

                                                                不关闭描述符

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <wait.h>

int main(){
    int fd[2];
    int ret=pipe(fd);
    if(ret<0){
        perror("pipe");
        return 0;
    }
    pid_t pid=fork();
    if(pid<0){
        perror("fork");
        return 0;
    }else if(pid==0){
        //child
        //子进程进行接受
        char buf_read[1024]={0};
        read(fd[0],buf_read,sizeof(buf_read)-1);
        printf("The content is :%s\n",buf_read);
    }else{
        //father
        //父进程发送数据
        char buf_write[]="success!";
        write(fd[1],buf_write,strlen(buf_write));
        wait(NULL);
    }
    return 0;
}

                                                                运行结果

        我们可以看出来在父进程向管道写入信息,在子进程读取管道信息. 

                                                          关闭描述符

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <wait.h>

int main(){
    int fd[2];
    int ret=pipe(fd);
    if(ret<0){
        perror("pipe");
        return 0;
    }
    pid_t pid=fork();
    if(pid<0){
        perror("fork");
        return 0;
    }else if(pid==0){
        //child
        //子进程进行接受
        close(fd[1]);
        char buf_read[1024]={0};
        read(fd[0],buf_read,sizeof(buf_read)-1);
        printf("The content is :%s\n",buf_read);
    }else{
        //father
        //父进程发送数据
        close(fd[0]);
        char buf_write[]="success!";
        write(fd[1],buf_write,strlen(buf_write));
        wait(NULL);
    }
    return 0;
}

                                                        运行结果 

                我们可以看出依旧可以进行读写~原因是什么呢?

        2.站在文件描述符角度-深度理解管道

 

        首先父进程创建管道,系统默认打开三个文件:标准输入,标准输出,和标准错误;创建管道则有fd[0],fd[1];分别表示管道的读端和写端;

         然后父进程创建子进程,子进程拷贝父进程,也拷贝了管道信息;所以父子进程共享管道;

         父进程关闭读端,子进程关闭写端,但是管道是共享的,依旧可以进行信息交互;

        3.站在内核角度-管道本质

 看待管道,就如同看待文件一样!管道的使用和文件一致,迎合了“Linux一切皆文件思想”。

        4.管道读写规则

        当没有数据可读时O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。

        当管道满的时候O_NONBLOCK disable: write调用阻塞,直到有进程读走数据O_NONBLOCK enable:调用返回-1,errno值为EAGAIN如果所有管道写端对应的文件描述符被关闭,则read返回0   

        如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE,进而可能导致write进程退出

        当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。

        当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

        5.管道属性设置与阻塞验证       

        fcntl函数原型:

#include<unistd.h>
#include<fcntl.h>
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd ,struct flock* lock);

 (1)F_DUPFD

与dup函数功能一样,复制由fd指向的文件描述符,调用成功后返回新的文件描述符,与旧的文件描述符共同指向同一个文件。

(2)F_GETFD

读取文件描述符close-on-exec标志

(3)F_SETFD

将文件描述符close-on-exec标志设置为第三个参数arg的最后一位

(4)F_GETFL

获取文件打开方式的标志,标志值含义与open调用一致

(5)F_SETF

设置文件打开方式为arg指定方式

设置读端为非阻塞:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main(){
    int fd[2];
    int ret=pipe(fd);
    if(ret<0){
        perror("pipe");
        return 0;
    }
    pid_t pid=fork();
    if(pid<0){
        perror("fork");
        return 0;
    }else if(pid==0){
        //child 
        //关闭写端
        //设置读端为非阻塞属性
        //读
        close(fd[1]);
        int flag=fcntl(fd[0],F_GETFL);
        fcntl(fd[0],F_SETFL,flag|O_NONBLOCK);
        char buf_read[1024]={0};
        ssize_t read_size=read(fd[0],buf_read,sizeof(buf_read)-1);
        printf("read_size:%ld\n",read_size);
        perror("read");

    }else{
        //father
        //关闭读端
        //写关闭/不关闭
        close(fd[0]);
        close(fd[1]);
    }
    while(1){
        sleep(1);
    }
    return 0;
}

                                                                        运行结果为:

 设置写端非阻塞:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main(){
    int fd[2];
    int ret=pipe(fd);
    if(ret<0){
        perror("pipe");
        return 0;
    }
    pid_t pid=fork();
    if(pid<0){
        perror("fork");
        return 0;
    }else if(pid==0){
        //child
        //关闭子进程读端
        //设置子进程写段为非阻塞
        //子进程写
        close(fd[0]);
        int flag=fcntl(fd[1],F_GETFL);
        fcntl(fd[1],F_SETFL,flag|O_NONBLOCK);
        ssize_t write_size;
        while(1){
            write_size=write(fd[1],"a",1);
            if(write_size<0){
                break;
            }
        }
        printf("write_size:%ld\n",write_size);
    }else{
        //father
        //关闭父进程写端
        //关闭父进程读端/不关闭
        close(fd[1]);
        //close(fd[0]);
        while(1){
            sleep(1);
        }
    }
    return 0;
}

                                                运行结果:

         6.管道特点(匿名)

        只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;

        通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道。

        管道提供流式服务一般而言,进程退出,管道释放,所以管道的生命周期随进程一般而言,内核会对管道操作进行同步与互斥管道是半双工的;

        数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;

        2.命名管道

        管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。

        如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。

        命名管道是一种特殊类型的文件

        1.创建一个命名管道

$ mkfifo pipe1

执行结果: 

也可以程序创建

函数原型:

#include<sys/types.h>
#include<sys/stat.h>
int mkfifo(const char *filename,mode_t mode);

                                        代码如下: 

#include <stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
int main(){
    mkfifo("pipe2",0664);
    return 0;
}

                                        运行结果

        2.命名管道的打开规则 

        如果当前打开操作是为读而打开FIFO时

        O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO

        O_NONBLOCK enable:立刻返回成功如果当前打开操作是为写而打开FIFO时

        O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO 

        O_NONBLOCK enable:立刻返回失败,错误码为ENXIO                

 3.匿名管道与命名管道的区别

        匿名管道由pipe函数创建并打开。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux管道 的相关文章

  • 如何为 Linux 桌面条目文件指定带有相对路径的图标?

    对于我的一个 Linux 应用程序 我有应用程序二进制文件 一个 launcher sh 脚本 针对 LD LIBRARY PATH 和一个 desktop 文件 所有这些都位于同一文件夹中 我想使用图标的相对路径而不是绝对路径 我试过了
  • 通过 Visual Studio 2017 使用远程调试时 Linux 控制台输出在哪里?

    我的Visual Studio 2017 VS2017 成功连接Linux系统 代码如下 include
  • Linux 上的 Pervasive ODBC 错误 [01000][unixODBC][驱动程序管理器]无法打开 lib '/usr/local/psql/lib/odbcci.so':找不到文件

    我正在尝试让 Pervasive v10 客户端 ODBC 在 Centos 6 上运行 据我所知 没有 64 位 ODBC 客户端 因此我必须使用 32 位客户端 我终于成功安装了它 但尝试使用时出现以下错误 isql v mydsn 0
  • 如何在linux中以编程方式获取dir的大小?

    我想通过 C 程序获取 linux 中特定目录的确切大小 我尝试使用 statfs path struct statfs 但它没有给出确切的大小 我也尝试过 stat 但它返回任何目录的大小为 4096 请建议我如何获取 dir 的确切大小
  • 从 ttyUSB0 写入和读取,无法得到响应

    我对 Linux tty 不太有经验 我的环境是带有丰富 USB 串行的 Raspbian 什么有效 stty F dev ttyUSB0 38400 cu l dev ttyUSB0 s 38400 cu to dev ttyUSB0作品
  • GMail 421 4.7.0 稍后重试,关闭连接

    我试图找出为什么它无法使用 GMail 从我的服务器发送邮件 为此 我使用 SwiftMailer 但我可以将问题包含在以下独立代码中
  • 使用非规范地址检索内存数据会导致 SIGSEGV 而不是 SIGBUS

    我无法使用以下汇编代码产生 总线错误 这里我使用的内存地址不是合法的 规范地址 那么 我怎样才能触发该错误呢 我在带有 NASM 2 14 02 的 Ubuntu 20 04 LTS 下运行这段代码 但它会导致负载出现 SIGSEGV 分段
  • 为什么 fopen("any_path_name",'r') 不给出 NULL 作为返回值?

    在调试一些代码时 我得到如下内容 include
  • 使用包管理器时如何管理 Perl 模块?

    A 最近的问题 https stackoverflow com questions 397817 unable to find perl modules in intrepid ibex ubuntu这让我开始思考 在我尝试过的大多数 Li
  • 从 Xlib 转换为 xcb

    我目前正在将我的一个应用程序从 Xlib 移植到 libxcb 但在查找有关我有时使用的 XInput2 扩展的信息时遇到了一些麻烦 libxcb 中有 XInput2 实现吗 如果是的话 在哪里可以找到文档 目前我在使用此功能时遇到问题
  • 静态方法的 Java 内存模型

    我来自操作系统和 C 语言背景 在代码编译时 世界很简单 需要处理和理解堆栈 堆文本部分等 当我开始学习 Java 时 我确实了解 JVM 和垃圾收集器 我对静态方法感到很有趣 根据我的理解 类的所有实例都会在堆中创建 然后被清理 但是 对
  • 如何在 Linux 中使用 C 语言使用共享内存

    我的一个项目有点问题 我一直在试图找到一个有据可查的使用共享内存的例子fork 但没有成功 基本上情况是 当用户启动程序时 我需要在共享内存中存储两个值 当前路径这是一个char and a 文件名这也是char 根据命令参数 启动一个新进
  • 错误:“rjags”的包或命名空间加载失败

    在终端的 conda 环境之一中 我能够成功安装包 rjags 但是 当我在该环境中运行 R 并运行库 rjags 时 出现以下错误 加载所需的包 coda 错误 rjags 的包或命名空间加载失败 rjags 的 loadNamespac
  • 使用os.execlp时,为什么`python`需要`python`作为argv[0]

    代码是这样的 os execlp python python child py other args this works os execlp python child py other args this doesn t work 我读过
  • 从 Linux 内核模块中调用用户空间函数

    我正在编写一个简单的 Linux 字符设备驱动程序 以通过 I O 端口将数据输出到硬件 我有一个执行浮点运算的函数来计算硬件的正确输出 不幸的是 这意味着我需要将此函数保留在用户空间中 因为 Linux 内核不能很好地处理浮点运算 这是设
  • 使用自定义堆的类似 malloc 的函数

    如果我希望使用自定义预分配堆构造类似 malloc 的功能 那么 C 中最好的方法是什么 我的具体问题是 我有一个可映射 类似内存 的设备 已将其放入我的地址空间中 但我需要获得一种更灵活的方式来使用该内存来存储将随着时间的推移分配和释放的
  • express.js api 应用程序中的内存泄漏

    我正在运行一个express js应用程序 它用作REST API 一个端点启动 puppeteer 并使用多个过程测试我的网站 启动应用程序并持续消耗端点后 我的 docker 容器每小时都会耗尽内存 如下所示 首先 我认为我的 pupp
  • 跨 CPU 内核的 rdtsc 精度

    我从一个线程发送网络数据包 并在运行于不同 CPU 核心上的第二个线程上接收回复 我的流程测量每个数据包发送和接收之间的时间 类似于 ping 我使用 rdtsc 来获得高分辨率 低开销的计时 这是我的实现所需要的 所有测量结果看起来都很可
  • 如何在Linux中自动启动需要X的应用程序

    我试图在系统进入运行级别 5 时自动启动 X 应用程序 这样做的正确方法是什么 我写了一个脚本并将其放在 etc init d 中 我已运行适当的 chkconfig 命令来设置 etc rcX d 目录中的符号链接 一切工作正常 除了当我
  • 如何找到进程启动时使用的原始用户名?

    有一个 perl 脚本需要以 root 身份运行 但我们必须确保运行该脚本的用户最初没有以用户 foo 身份登录 因为它将在脚本运行期间被删除 那么 我如何查明自登录以来可能已多次起诉的用户是否在该链中的任何时间都没有模拟过 foo 我发现

随机推荐

  • 无人机飞行控制实验平台

    无人机在研制过程中需要不断地进行飞行测试 xff0c 而测试的过程不是万无一失的 xff0c 飞行过程中发生任何错误都有可能会导致无人机的损毁或破坏 xff0c 更严重地甚至会造成外界伤害 基于此我们推出了无人机的三旋转自由度 3 DOF
  • ADS-B教学实验方案

    ADS B教学系统是为了让学生学习ADS B原理 ADS B系统组成 ADS B信号处理技术 可以通过ADS B教学系统进一步研究分析ADS B位置的精度 准确性 稳定性 实时性 xff0c 设计基于ADS B的空中碰撞告警系统 xff0c
  • ROS系列:工作空间及功能包创建

    前言 分享一下ROS开发的基础教程 xff0c 全部自己手敲 xff0c 希望能帮到正在学习的你 ROS在WIKI上也有教程 xff0c 个人觉得太过臃肿 xff0c 可以简化点 xff0c 毕竟大家都赶着投胎 xff0c 哈哈哈哈哈 一
  • java UDP DatagramSocket接收不到数据

    今天联系这个通信 xff0c 接收端总是接收不到数据 xff01 排除代码本身有可能出现的错误 xff0c 比如地址 xff0c 数据宝包 我称它为数据宝宝 xff09 等等自己粗心的错误后还是不行 xff0c 我查看各种方法 xff0c
  • Python与爬虫有什么关系?

    爬虫一般是指网络资源的获取 xff0c 因为python的脚本特征 xff0c Python易于配置 xff0c 对字符的处理也非常灵活 xff0c 加上python有丰富的网络抓取模块 xff0c 所以两者经常联系在一起 接下来我们可以详
  • C++中struct和class的区别

    1 C 43 43 中struct和class的区别 C 43 43 中的struct其实是为了与C的兼容性而留下来的 C 43 43 的struct和class其实大部分都是相同的用法 xff0c 基本上可以用class做的事都可以用st
  • L298N驱动步进电机,有stm32代码亲测可用

    1 1 步进电机相关概念 相数 xff1a 产生不同对极N S磁场的激磁线圈对数 xff0c 常用 m 表示 例如 xff1a 二相四线电机 xff0c 就有两对极N S磁场的激磁线圈 xff0c 四个线圈 上图可知 xff0c A 43
  • C++成员初始化

    C 43 43 成员分为 xff1a 一般变量 xff0c const修饰变量 xff0c 引用类型成员 xff0c static成员 xff0c const staic成员 同static const xff0c 自定义类型对象 clas
  • HTTP协议解析

    目录 1 HTTP协议的概念 2 HTTP协议格式 3 HTTPS 1 HTTP协议的概念 在我们之前学习网络的过程中 xff0c 我们知道了目前主流网络分层模型共分为5层 xff0c 分别是物理层 xff0c 数据链路层 xff0c 网络
  • cmake编译opencv开源项目报错问题

    最近使用cmake在编译一个配置了opencv环境的c 43 43 开源项目时遇到如下问题 CMake Warning at D opencv4 OpenCVConfig cmake 176 message Found OpenCV Win
  • Ubuntu系统换源

    简单介绍一下源 xff0c 源就是一个大仓库 xff08 类似应用商店 xff09 xff0c 系统下载软件需要从这个仓库下载 xff0c 因为Ubuntu默认源是国外的 xff0c 所以在下载东西的时候会出现下载速度很慢的情况 xff0c
  • 字符串的简单介绍和字符串的大小比较

    以前就写过一篇关于String的文章 xff0c 今天再来写一篇 xff0c 更加深入了解一下String类 x1f550 1 String类的定义 x1f551 2 String类的创建 x1f552 3 字符串的大小比较 1 之前在C语
  • 数据结构1

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
  • 洛谷P5740 【深基7.例9】最厉害的学生

    题目描述 现有 N N le 1000 N N 1000 名同学参加了期末考试 xff0c 并且获得了每名同学的信息 xff1a 姓名 xff08 不超过 8 个字符的仅有英文小写字母的字符串 xff09 语文 数学 英语成绩 xff08
  • C语言创建链表并输出

    代码如下 define CRT SECURE NO WARNINGS include lt stdio h gt include lt assert h gt include lt string h gt include lt stdlib
  • 游戏搬砖是什么意思?

    网络游戏搬砖是指在各网络游戏中 xff0c 玩家把花大量时间 精力赚的钱转手为游戏买各种东西 搬砖原本是一个汉语词语 xff0c 意思是原指搬运砖块 xff0c 在网络语中 xff0c 搬砖引申为工作辛苦 重复机械 赚钱不多的工作 在一些方
  • C语言实现扫雷游戏

    话不多说直接淦代码 代码都有详细注释 define CRT SECURE NO WARNINGS include lt stdio h gt include lt time h gt include lt stdlib h gt inclu
  • C语言用栈实现队列(数据结构)

    1 首先需要两个栈来模拟队列的出队和入队 2 假设入队1 2 3 4 如果要出队则不能直接出栈 需要进行数据的搬移 先把s1的数据全部放入s2中 然后再在s2出栈 gt 整个队列出队 3 如果再要入队则将入队元素放入s1 若要出队则出栈s2
  • Linux权限理解(详细详细)

    目录 一 权限的概念 二 Linux权限管理 1 文件访问者的分类 xff08 人 xff09 2 文件类型和访问权限 xff08 事物属性 xff09 3 文件权限值的表示方法 1 字符表示 2 8进制数字表示法 4 文件访问权限的相关设
  • Linux管道

    目录 1 管道概念 2 管道分类 1 匿名管道 1 基本实现与概念 2 站在文件描述符角度 深度理解管道 3 站在内核角度 管道本质 4 管道读写规则 5 管道属性设置与阻塞验证 6 管道特点 匿名 2 命名管道 1 创建一个命名管道 2