进程间通信——重定向、描述符表

举报
yd_221104950 发表于 2020/12/03 01:01:42 2020/12/03
【摘要】 在命令行运行程序时,可以用“>"运算符把标准输出重定向到文件: ~/Desktop/Mc$ echo "hello world" > log.txt ~/Desktop/Mc$ tail -f log.txt hello world 123 标准输入、标准输出、标准错误是三大默认数据流,除此之外还有其他形式的数据流,如文件连接和网络连接也属于数据流。数据流就是流动的...

在命令行运行程序时,可以用“>"运算符把标准输出重定向到文件:

~/Desktop/Mc$ echo "hello world" > log.txt
~/Desktop/Mc$ tail -f log.txt
hello world

  
 
  • 1
  • 2
  • 3

标准输入、标准输出、标准错误是三大默认数据流,除此之外还有其他形式的数据流,如文件连接和网络连接也属于数据流。数据流就是流动的数据,数据从一个进程流出,然后流入另一个进程。

重定向进程的输出,相当于改变进程发送数据的方向。如上面的例子,原本标准输出会把数据发送到屏幕,现在让它把数据发送到文件。

进程含有它正在运行的程序,还有栈和堆空间。除此之外,进程还需要记录数据流的连向,比如标准输出连到了哪里。这些记录记在哪里呢?答案就是描述符表。进程用文件描述符表示数据流,所谓的描述符其实就是一个数字。进程会把文件描述符和对应的数据流保存在描述符表中。

描述符表

数据流
0 键盘
1 屏幕
2 屏幕

描述符表的一列是文件描述符号,另一列是它们对应的数据流。虽然名字叫文件描述符,但它们不一定连接硬盘上的某个文件,也可能连接键盘、屏幕、文件指针、网络。

描述符表的前三项是不会变的:0号标准输入、1号标准输出、2号标准错误。其他项要么为空,要么连接进程打开的数据流。比如程序在打开文件进行读写时,就会占用其中一项。描述符表的大小是从0到255号。

创建进程以后,标准输入连接到键盘,标准输出和标准错误连接到屏幕。它会保持这样的连接,直到有人把它们重定向到了其他地方。

重定向就是替换数据流

标准输入/输出/错误在描述符表中的位置是固定的,但它们指向的数据流是可以改变的。例如想重定向标准输出,只需要修改表中1号描述符对应的数据流就OK了。

数据流
0 键盘
1 屏幕 log.txt
2 屏幕

所有向标准输出发送数据的函数会先查看描述符表,看1号描述符指向哪条数据流,然后再把数据写到这条数据流中,printf()函数就是这样。

进程可以重定向自己

在命令行中可以用“>“和”<"运算符重定向程序。进程也能重定向它们自己,只需修改描述符表。只需要两步就可以实现:

1.fileno()返回文件描述符号
每打开一个文件,操作系统都会在描述符表中新注册一项。假设我们打开了log.txt文件:

 FILE *my_file = fopen("log.txt","w");

  
 
  • 1

操作系统会打开log.txt文件,然后返回一个指向它的指针,操作系统还会遍历描述符表找空项,把新文件注册在其中。

int descriptor = fileno(my_file);

  
 
  • 1

在失败时不返回-1的函数很少,fileno()就是其中之一。只要你把打开文件的文件指针传给fileno(),它就一定会返回描述符编号。

2.dup2()复制数据流
每次打开文件都会使用描述符表中新的一项。但如果你想修改某个已经注册过的数据流,比如让1号文件描述符重新指向其他数据流,就可以用dup2()函数来实现,dup2()可以复制数据流,假设我们在3号文件描述符中注册了log.txt文件指针,下面代码就可以同时把文件指针连接到1号描述符:

dup2(3,1);

  
 
  • 1
数据流
0 键盘
1 屏幕 log.txt文件
2 屏幕
3 log.txt文件

虽然log.txt文件只有一个,与它相连的数据流也只有一个,但是数据流(FILE *)同时注册在文件描述符1和3中。所以标准输出都会被重定向到文件log.txt中。

我们看一个完整的实例:

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main(){ FILE *my_file = fopen("log.txt","w"); int descriptor = fileno(my_file); dup2(descriptor,1); printf("Hello world,I love you!\n"); return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

编译运行:

~/Desktop/MyC$ gcc test4.c -o test4
~/Desktop/MyC$ ./test4
~/Desktop/MyC$ tail -f log.txt
Hello world,I love you!

  
 
  • 1
  • 2
  • 3
  • 4

用管道连接输入与输出,符号“|”表示管道(pipe),它能连接一个进程的标准输出与另一个进程的标准输入。
如:

~/Desktop/MyC$ ls /usr/include | grep stdio
stdio_ext.h
stdio.h

  
 
  • 1
  • 2
  • 3

ls程序的标准输出会连接到grep程序的标准输入。

谢谢阅读!

文章来源: blog.csdn.net,作者:WongKyunban,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/weixin_40763897/article/details/87545788

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。