Linux管道学习(无名管道)

2024-01-26 04:04
文章标签 linux 学习 管道 无名

本文主要是介绍Linux管道学习(无名管道),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

       

目录

1、概述

2、管道的创建

3、管道读写行为

3.1、管道读


        在linux中管道有两种,一是无名管道(匿名管道),第二种是有名管道;无名管道主要用于有血缘关系的父子进程间通信,有名管道则不受该限制,可用于任意进程之间的通信;这里我们主要学习无名管道。

1、概述

        创建无名管道的函数如下:

#include <unistd.h>
int pipe(int pipefd[2]);

        调用失败返回-1,成功返回0;调用成功时该函数会创建一个单向的管道用于进程之间的通讯,返回的管道包含读端和写端,其中fd[0]用于读,fd[1]用于写,写到fd[1]的数据会被内核保存到缓冲区,直到fd[0]读走数据。

2、管道的创建

        代码如下:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>int main(int argc, char *argv[]) {pid_t fd[2];int ret;ret = pipe(fd);	if (-1 == ret) {perror("pipe error!\n");	exit(1);}printf("Hello pipe, fd[0] = %d, fd[1] = %d\n", fd[0], fd[1]);return 0;
}

        很简单,直接调用pipe并传入一个文件描述符数组,如果出错则退出,调用成功则返回两个可用的文件描述符,其中fd[0]用于读,fd[1]用于写。

        gcc编译:gcc pipe.c -o pipe,运行./pipe得出如下运行结果:

3、管道读写行为

        由于管道是单向通讯的,所以在使用的时候会有一些限制。

  • 管道读

如果管道中有数据,则读取实际能读到的数据;

如果管道中无数据,此时有两种情况:一是有管道写端,此时会阻塞直到写端写入数据;二是没有管道写端(写端被关闭),因为没有写端,永远不会有数据写入,此时返回0。

  • 管道写

如果管道满了,则写阻塞,直到能写入。

如果管道未满,此时有两种情况:一是没有管道读端,此时异常终止(SIGPIPE导致);二是有读端,则返回实际写入的字节数。

        下面简单列举几个例子,主要是父子进程之间通讯。

3.1、管道读

         代码如下:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>int main(int argc, char *argv[]) {pid_t fd[2];int ret;char buf[1024];char *info = "Hello Pipe(from read)\n";ret = pipe(fd);	if (-1 == ret) {perror("pipe error!\n");	exit(1);}ret = fork();if (0 == ret) {printf("I'm child\n");close(fd[1]);while ((ret = read(fd[0], &buf, 1024)) > 0) {write(STDOUT_FILENO, &buf, ret);}close(fd[0]);} else if (ret > 0) {printf("I'm parent\n");close(fd[0]);write(fd[1], info, strlen(info));close(fd[1]);} else {perror("fork error!\n");exit(1);}return 0;
}

         首先调用pipe创建了读写管道的读端和写端,然后调用fork创建了一个子进程,如果ret 为0,说明是在子进程,如果ret大于0,说明是在父进程,如果ret小于0则说明fork出错,退出程序。

        代码中申明了一个字符串"Hello Pipe(from read)",由于父进程用于写,子进程用于读,所以父进程首先关闭了fd[0],然后用fd[1]往管道中写入"Hello Pipe(from read)",之后关闭fd[1]。

        由于子进程用于读,所以一开始关闭了管道的写端fd[1],然后循环从fd[0]中读入数据存储到buf中并打印到屏幕,直到读完管道中的数据,最后关闭管道读端fd[0]。

        运行结果如下:

        上面演示的是管道有数据的情况,立刻就读出了管道中的数据;下面考虑以下两种情况

  1. 管道无数据 有写端
  2. 管道无数据 有读端

        第一种情况,管道将会读阻塞,可以运行如下实例看看:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>int main(int argc, char *argv[]) {pid_t fd[2];int ret;char buf[1024];char *info = "Hello Pipe(from read)\n";ret = pipe(fd);	if (-1 == ret) {perror("pipe error!\n");	exit(1);}ret = fork();if (0 == ret) {printf("I'm child\n");close(fd[1]);while ((ret = read(fd[0], &buf, 1024)) > 0) {write(STDOUT_FILENO, &buf, ret);}close(fd[0]);printf("After read\n");} else if (ret > 0) {printf("I'm parent\n");close(fd[0]);//write(fd[1], info, strlen(info));sleep(10);printf("After sleep\n");close(fd[1]);} else {perror("fork error!\n");exit(1);}return 0;
}

        代码结构和之前一样,为了构造管道无数据的情况,父进程中没有写入数据,而是sleep(10),然后10s后输出"After sleep"且关闭管道写端fd[1];子进程保持不变,由于管道中一直没有数据,会导致子进程管道的读端一直阻塞直到父进程关闭管道写端fd[1]。

        程序输出如下:

        

这篇关于Linux管道学习(无名管道)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/645586

相关文章

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

Linux云服务器手动配置DNS的方法步骤

《Linux云服务器手动配置DNS的方法步骤》在Linux云服务器上手动配置DNS(域名系统)是确保服务器能够正常解析域名的重要步骤,以下是详细的配置方法,包括系统文件的修改和常见问题的解决方案,需要... 目录1. 为什么需要手动配置 DNS?2. 手动配置 DNS 的方法方法 1:修改 /etc/res

Linux创建服务使用systemctl管理详解

《Linux创建服务使用systemctl管理详解》文章指导在Linux中创建systemd服务,设置文件权限为所有者读写、其他只读,重新加载配置,启动服务并检查状态,确保服务正常运行,关键步骤包括权... 目录创建服务 /usr/lib/systemd/system/设置服务文件权限:所有者读写js,其他

Linux下利用select实现串口数据读取过程

《Linux下利用select实现串口数据读取过程》文章介绍Linux中使用select、poll或epoll实现串口数据读取,通过I/O多路复用机制在数据到达时触发读取,避免持续轮询,示例代码展示设... 目录示例代码(使用select实现)代码解释总结在 linux 系统里,我们可以借助 select、

Linux挂载linux/Windows共享目录实现方式

《Linux挂载linux/Windows共享目录实现方式》:本文主要介绍Linux挂载linux/Windows共享目录实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录文件共享协议linux环境作为服务端(NFS)在服务器端安装 NFS创建要共享的目录修改 NFS 配

linux系统中java的cacerts的优先级详解

《linux系统中java的cacerts的优先级详解》文章讲解了Java信任库(cacerts)的优先级与管理方式,指出JDK自带的cacerts默认优先级更高,系统级cacerts需手动同步或显式... 目录Java 默认使用哪个?如何检查当前使用的信任库?简要了解Java的信任库总结了解 Java 信

Linux命令rm如何删除名字以“-”开头的文件

《Linux命令rm如何删除名字以“-”开头的文件》Linux中,命令的解析机制非常灵活,它会根据命令的开头字符来判断是否需要执行命令选项,对于文件操作命令(如rm、ls等),系统默认会将命令开头的某... 目录先搞懂:为啥“-”开头的文件删不掉?两种超简单的删除方法(小白也能学会)方法1:用“--”分隔命

Linux五种IO模型的使用解读

《Linux五种IO模型的使用解读》文章系统解析了Linux的五种IO模型(阻塞、非阻塞、IO复用、信号驱动、异步),重点区分同步与异步IO的本质差异,强调同步由用户发起,异步由内核触发,通过对比各模... 目录1.IO模型简介2.五种IO模型2.1 IO模型分析方法2.2 阻塞IO2.3 非阻塞IO2.4