首页 > linux进程间通信:shell管道 | 的实现

linux进程间通信:shell管道 | 的实现

文章目录

      • 介绍
      • 重定向函数介绍
      • 总结


linux terminal输入如下命令,其中"|"符号即为我们上文中所说的无名管道

在这里插入图片描述

介绍

正如我们上文中所描述的"|“无名管道提供了具有亲缘关系的进程之间的通信,它由于直接使用系统调用,运行效率较高。则linux系统下可以大批量的使用”|"来提供命令直接输入输出的重定向。

具体shell中管道的实现可以参考如下图:

在这里插入图片描述

当我们直接执行lsmod时,此时进程文件描述符默认会打开标准输入,标准输出,标准错误三个文件。lsmod的输出内容会写到标准输出设备,即linux terminal显示屏。当我们加入了管道,其最终将标准输出重定向到管道的f[1]写描述符。

具体流程如下:

a. 将命令封装成进程:通过fork/exec系统调用

b. 该进程此时会默认打开stdin 0 ,stdout 1 ,sdterr 2 连接到终端上

c. 运行的命令从键盘读取数据并且把输出和错误消息写到屏幕上(标准输出一般默认是屏幕)

d. 通过重定向,可以从指定文件读取数据,或将数据输出到指定文件

e. 重定向IO的功能是由shell本身实现,标准流与文件连接

f. 程序本身并不知道数据最后流向哪里,他只知道将自身输出写到标准输出中

g. 通过命令:cmd > file 告诉shell将stdout定位到的文件file,于是shell就将文件描述符与指定的文件连接起来,程序将输出放入file而不是默认的屏幕

重定向函数介绍

如下三个函数

#include 
int dup(int oldfd); //将old文件描述符重定向给返回值
int dup2(int oldfd, int newfd); //重定向成功,则返回重定向后新的文件句柄#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include               /* Obtain O_* constant definitions */
#include 
int dup3(int oldfd, int newfd, int flags);

以上dup,dup2,dup3函数在shell中实现了将输入输出设备和管道联系了起来,将输入输出重定向到具体文件之中

  • int dup(int oldfd)

    其中dup函数实现了将旧的文件描述符拷贝给新的文件描述符,此时old_fd和new_fd将会共享同一个文件的状态标记(读写权限等),文件偏移地址等

    #include 
    #include 
    #include 
    #include 
    #include int main()
    { int fd,new_fd;//打开文件fd = open("write.txt",O_RDWR | O_CREAT,777);if(fd == -1){ perror("open failed");exit (-1);}//将fd文件描述符拷贝到新的文件描述符,两个文件描述符共享同一个文件new_fd = dup(fd);write(fd, "hello",strlen("hello"));write(new_fd, "world", strlen("world"));write(fd, "zhang", strlen("world"));//紧接着new_fd对文件写操作之后的偏移地址进行写close(fd);close(new_fd);return 0;
    }
    

    如果我们将以上中new_fd置为1(1的文件句柄代表标准输出),则write的结果将输出到屏幕

    如下代码:

    #include 
    #include 
    #include 
    #include int main()
    { int new_fd;new_fd = dup(1); //将new_fd重定向到标准输出,即copy一个标准输出到new_fdwrite(1,"hello",strlen("hello"));write(new_fd,"world
    ",strlen("wrold
    ")); //此时操作系统为该进程文件重新分配一个文件句柄3,因为0,1,2已经被占用//printf("new_fd = %d
    ",new_fd);close(new_fd);return 0;
    }
    
  • int dup2(int old_fd,int new_fd)

    dup2函数和dup函数可以指定 我们想要重定向到的文件句柄,比如我们想将标准输出重定向到指定的文件

    查看如下代码:

    #include 
    #include 
    #include 
    #include 
    #include int main()
    { int fd,new_fd;char *ptr = "hello world
    ";fd = open("data.log",O_RDWR | O_CREAT,664);if (fd == 0) { perror("open failed");exit(-1);}new_fd = dup2(fd,1); //将标准输出重定向到fd文件句柄,即data.log文件if (new_fd == -1) { perror("open failed ");exit(-1);}printf("fd : %d 
     new_fd :%d
    ",fd,new_fd); //同样是标准输出,那么它的输出也会输出到 fd文件句柄。同时对new_fd的操作即为对标准输出的操作write(1,ptr,strlen(ptr));write(new_fd,"i am new
    ",strlen("i am new
    "));//向new_fd中写入,即向标准输出中写入,但是此时标准输出已经重定向到了data.log中close(fd);return 0;
    }
    

    输出如下:

    此时这个输出很有意思,可以发现c语言的面向过程式有点不太对,为什么write(" i am new")是在printf之后调用,但是它的输出结果确是在prinf前输出呢?这里很明显,printf函数的同样是标准输出,但是它是在程序执行完成之后将结果重定向到标准输出的,而我们调用write(“i am new”)确是已经在运行过程中将结果通过标准输出重定向到文件,所以此时printf的输出会晚于用重定向函数的结果

    [root@node1 /]# cat data.log 
    hello world
    i am new
    fd : 3 new_fd :1
    

    通过管道以及重定向实现如下操作lsmod |grep snd

    基本流程如下

    在这里插入图片描述

    #include 
    #include 
    #include 
    #include 
    #include int main()
    { int pipe_fd [2]; if (pipe(pipe_fd) == -1) { //创建一个管道perror("pipe");exit (-1);} else { int ret;ret = fork();if (ret == 0) {  //标准输出重定向到管道的写端,即lsmod的输出将重定向到f[1]dup2(pipe_fd[1],1);execlp("lsmod","lsmod",NULL,NULL);}else { dup2(pipe_fd[0],0); //从f[0]读出f[1]写入的内容到标准输入close(pipe_fd[1]); execlp("grep","grep","snd",NULL);}}return 0;
    }
    

总结

通过以上探讨,我们了解了linux shell中管道以及重定向符的实现原理,通过dup系列函数对进程文件句柄的复制实现。有意思~

更多相关:

  • fifo的双向通信的方式如下图: 两个进程间的通信需要两个命名管道,分别处理一个进程的读和写 导致这种通信方式出现的根因还是由于fifo的阻塞读和阻塞写,所以这里需要使用两个管道对读写进行分别处理。 同时因为管道传输的数据为流式数据,则无法对数据进行指定标记(数据的发送者,接受者,大小。。。)。 SERVER端代码如下: /*...

  • 2019独角兽企业重金招聘Python工程师标准>>> fd_set 结构,是一个数字。 文件描述符fd的值 不能超过1024,而不是数量不能超过1024。 在开发打开句柄多的程序时,最好不要使用select。否则就使用多进程开发。 /usr/include/X11 Xpoll.h 文件 #ifndef _XPOLL_H_#...

  • 全卷积网络(FCN) 1.全卷积神经网络介绍 FCN对图像进行像素级的分类,从而解决了语义级别的图像分割(semantic segmentation)问题。与经典的CNN在卷积层之后使用全连接层得到固定长度的特征向量进行分类(全联接层+softmax输出)不同,FCN可以接受任意尺寸的输入图像,采用反卷积层对最后一个卷积层的fea...

  • printf()函数优点在于可以格式化输出 格式:   %['padding_character][-][width][.precision]type   所有的转换说明都是以%开始,如果想打印一个%符号,必须用%% ;   参数“'padding_character”是可选,它将被用来填充变量直至所指定的宽度,该参...

  • 给定一个长度不超过10000的、仅由英文字母构成的字符串。请将字符重新调整顺序,按GPLTGPLT....这样的顺序输出,并忽略其它字符。当然,四种字符(不区分大小写)的个数不一定是一样多的,若某种字符已经输出完,则余下的字符仍按GPLT的顺序打印,直到所有字符都被输出。 输入格式: 输入在一行中给出一个长度不超过10000的、仅...

  • 给定两个整数A和B,输出从A到B的所有整数以及这些数的和。 输入格式: 输入在一行中给出2个整数A和B,其中−100≤A≤B≤100,其间以空格分隔。 输出格式: 首先顺序输出从A到B的所有整数,每5个数字占一行,每个数字占5个字符宽度,向右对齐。最后在一行中按Sum = X的格式输出全部数字的和X。 输入样例:...

  • python面试题目 原文地址:https://www.usblog.cc/blog/post/justzhl/b5cc9a05c7d2 问题一:以下的代码的输出将是什么? 说出你的答案并解释。 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Parent(object):     x...

  • 本文来自 运维人生 ,作者:fly是个稻草人链接:http://www.ywadmin.com/?id=76误删除linux系统文件了?不用急,本文将给你一个恢复linux文件的方法,让你轻松应对运维中的各风险问题。方法总比问题多~说在前面的话针对日常维护操作,难免会出现文件误删除的操作。大家熟知linux文件系统不同win有回收...

  • 原文来自SecIN社区—作者:WiHat0x00 什么是WebShell渗透测试工作的一个阶段性目标就是获取目标服务器的操作控制权限,于是WebShell便应运而生。Webshell中的WEB就是web服务,shell就是管理攻击者与操作系统之间的交互。Webshell被称为攻击者通过Web服务器端口对Web服务器有一定的操作权限,而...

  • 断电时文件系统发生了什么?硬盘又发生了什么?下一次开机时写到一半的文件在系统层面还在吗?在底层还在吗?更进一步的, 文件系统如何保证事务性, 会不会存在某种极端情况导致例如最后几个bit还没写完, 文件系统却认为它成功了的情况?回答不限任何文件系统,谢谢!下面是「北极」的回复分享断电的一瞬间,很多事情是无法确定的:1. 你无法确定...

  • 接到项目需求。需要搭建一个页面进行交互,慢慢来b (2).jpg使用python django框架进行页面的搭建在项目文件下打开窗口,输入命令;django-admin startproject helloword#在文件helloword/helloword/创建view.py在view.py文件中输入以代码from django....

  • 常见的错误集合解决方案(一)No.1提示错误'Microsoft.VC90.CRT,version="9.0.21022.8"把Microsoft.NET Framework 3.5.1下面的全部勾选上。No.2解决Qt Designer设计的图标但是VS生成不显示问题描述:在Qt designer中为菜单栏和工具栏设计的图标,但是...