最近写myshell的时候,用到了dup2这个函数,函数的形式看着很简单,但是当时就是很不理这么用的意义在哪里,不知道它具体是怎么实现重定向输入输出的。后来上网查了很多资料,从文件描述符开始来了解,想了想。
文件描述符
百度是这么说的:内核(kernel)利用文件描述符(file descriptor)来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。
所以开始理解文件描述符的时候只是知道它是计算机里面的一堆整数,就是一个代号,然后用到dup2函数的时候,就真的懵了,新的文件描述符号复制代替旧的文件描述符,不太理解一个符号的意义。
后来才知道其实文件描述符号是一个引索的符号,并且它是有一个指向的,重点是指向每一次内核所维护的进程打开过的文件的一个记录表。文件描述符号是会在那个记录表中建立一个引导检索的过程。
每一个进程都有一个进程ID号,通过打开/proct目录可以查看,在这个目录下,其实是一个虚拟的文件操作系统,它的每一个目录都是一个进程的id号,而且那个目录是经常发生变化的。当打开一个进程的时候,会有一些改变,通过以下截图,可以发现两次查看/proct目录,下面的子目录多了一个。
然后那些数字就是代表进程目录,一个进程有一个目录(当时第一眼就发现了数字为1的那个目录,其实就是当时了解孤儿进程时候,只要子进程成了孤儿进程后,都会托管给它的那个init,……我猜是,反正是进程目录……)
其实查看这个目录,是想打开看看进程目录下的文件描述符……
感觉没有说明什么,但是只是体验下这个文件描述符是什么存在形式的。
然后不是看上1这个目录了,就用root身份打开了1这个目录。百度了下,打开了这个目录下的fd目录,果然终于……看到了迷惑很久的文件描述符……
然后说明了什么……我感觉大概说明的就是一个进程会打开很多文件,然后内核会返回那堆文件的文件描述符,存在这个虚拟的文件系统中。
dup2的认识
对于内核来说,都是通过文件描述符去打开文件的,而标准输入输出都是文件。标准输出文件(stdout)和标准错误输出文件(stderr),这两个文件都对应终端的屏幕。进程将从标准输入文件中得到输入数据,将正常输出数据输出到标准输出文件,而将错误信息送到标准错误文件中。内核是不知道文件流的存在的,所以printf函数输出到stdout的东西最后都写入了文件描述符1中,在文件表中存在文件状态标志、当前文件偏移量、v节点指针,每个打开的文件描述符(fd标志)在进程表中都有自己的文件
表项,由文件指针指向它
当我了解到这里的时候,其实dup2( )这个函数也就很好理解它是怎么操作的了。
假如oldfd的值为1, 当前文件描述符的最小值为3, 那么新描述符3指向文件描述符1所拥有的文件表项。其实原来CGI程序使用dup2函数将STDOUT_FINLENO(宏为1)这个文件描述符重定向到了连接套接字。
在没有使用dup2的时候:
printf 将数据给 stdout 然后再交给 STDOUT_FILENO(宏为1的文件描述符) 最后才交给 终端
使用dup2的时候:
printf 将数据给 stdout 然后再交给 STDOUT_FILENO(宏为1的文件描述符) 最后才交给重定向的confid(个标识已连接套接口的描述字)感觉其中还涉及了管道,毕竟最后的输出已经指向了另外的文件描述符了。