进程间通信——重定向、描述符表
在命令行运行程序时,可以用“>"运算符把标准输出重定向到文件:
~/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 | |
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 | |
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
- 点赞
- 收藏
- 关注作者
评论(0)