LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 2620|回复: 4

文件描述符以及重定向分析

[复制链接]
发表于 2007-11-20 11:52:06 | 显示全部楼层 |阅读模式
谁能告诉我怎么样让我附件中的图片显示到它该显示的地方去吗?
在分析重定项之前先解释几个概念:

  • 文件描述符
  • 系统文件表
  • 内存中的索引结点表


什么是文件描述符?
      
首先从ISO C标准的I/O库说起.在C语言中使用的是文件指针而不是文件描述符做为I/O的句柄."文件指针(file pointer)"指向进程用户区中的一个被称为FILE结构的数据结构.例如下面的代码打开文件/home/adamzyg/linuxsir.cn做输出,然后向文件中写入一个字符串
  1.                 FILE *myfp;
  2.                 if ((myfp = fopen("/home/adamzyg/linuxsir.cn", "w")) == NULL)
  3.                         perror("Failed open /home/adamzyg/linuxsir.cn");
  4.                 else
  5.                         fprintf(myfp, "All the linuxsirs are so stupid!");
复制代码
     
下图显示(执行fopen.bmp)的是fopen调用分配的FILE结构原理图.FILE结构包括一个缓冲区和一个文件描述符值.而文件描述符值是文件描述符表中的一个索引.从某种意义上说文件指针就是句柄的句柄.文件描述符表存在于用户区,是针对某个进程而言的,其中的项也就是文件描述符,而这些描述符都对应一个整数的索引.比如shell进程默认会有三个文件描述符"STDIN","STDOUT","STDERR".它们对应的索引值就是STDIN_FILENO(0),STDOUT_FILENO(1),STDERR_FILENO(2).这些符号名定义在unistd.h中.
  1.                 /* Standard file descriptors.  */
  2.                 #define        STDIN_FILENO        0        /* Standard input.  */
  3.                 #define        STDOUT_FILENO        1        /* Standard output.  */
  4.                 #define        STDERR_FILENO        2        /* Standard error output.  */
复制代码
(执行fopen.bmp)

什么是系统文件表?
     
        系统文件表被系统中所有的进程共享,对每个活动的open,它都包含一个条目.每个系统文件表条目都包含文件偏移量,访问模式(即读,写或读-写)以及指向它的文件描述符表条目的计数.比如fork出一个子进程时,子进程就会继承父进程的文件描述符表.此时父子进程中的相同文件描述符就指向同一个系统文件表,因此子进程也就共享了父进程已经打开的文件(以及偏移量).如下图所示(父子进程共享文件描述符.bmp):

(父子进程共享文件描述符.bmp)

什么是内存中的索引结点表(in-memory inode table)?
内存中索引结点表是对系统中的每个活动文件而创建的一个唯一的条目.当程序打开一个当前没有打开的特定的物理文件时就会创建一个相应的条目出来.几个系统文件表项可能同时对应同一个内存中的索引结点表,也就是说这个内存中的索引结点表所对应的那个打开的文件被在不同的进程中都用到了(可能是为读/写/读-写打开).如下图所示(三种表项的关系.bmp):因此内存中的索引回对指向它的系统文件表进行计数,如果计数为0时(也就是说对应的物理文件已经无处用到时),就会从内存中删除它(可能不是立即删除).

(三种表项的关系.bmp)


好了,这三个概念解释完后,我们来看看重定向.
比如我们在命令行输入"ls > linuxsir.cn"

1. 在输入命令之前,shell默认的文件描述符表如下:
(shell默认文件描述符.bmp)
2. 解释命令行,如果命令是个磁盘上的可执行文件,就会演奏进程"三部曲"
(i). 系统调用fork. fork后文件描述符表如图父子进程共享文件描述符类似,只不过还没有D那项:

(ii). 系统调用wait().当子进程处理重定向,管道或后台处理等细节时,程序安排父进程进入睡眠.这里子进程要处理重定向"> linuxsir.cn".因此子进程以写方式打开文件linuxsir.cn(假如它获得的文件描述符为3),那么系统文件表以及内存中的索引结点表也会有对应的条目出现(如下图"子进程打开linuxsir.cn后.bmp").

(子进程打开linuxsir.cn后.bmp)
接着会将STDOUT_FILENO指向系统文件表的指针改指向打开linuxsir.cn对应的系统文件表,并把刚刚为linuxsir.cn临时打开的文件描述符关闭,如下图所示(改指系统文件表后.bmp):

(改指系统文件表后.bmp)
3. 系统调用exec
4. 系统调用exit.父进程睡醒.

注意: 上面的(ii)过程是我看到unix系统编程第4章UNIX
I/O时自己对重定向的一些猜想,不能确认是否是这样的一个过程.当然这本书那一节是为了模拟这样的过程(参见UNIX系统编程92页),而且中间提到在将STDOUT_FILENO指向系统文件表的指针改指向打开linuxsir.cn对应的系统文件表前会将STDOUT_FILENO原来指向的系统文件表关闭(使用用dup2的结果),这样做貌似不妥,因为父子进程共享着同一个系统文件表,这样一来岂不是把父进程的系统文件表也给干掉了.还有一钟情况不能解释,例如如果这里执行的命令是shell的内置命令时(也就是不发生fork时),比如输入"times > linuxsir.cn"或者"type ls > linuxsir.cn"时重定向是怎么做的,如果是将STDOUT_FILENO指向系统文件表的指针改指向打开linuxsir.cn对应的系统文件表,那岂不是把整个shell也给重定项了?事实肯定不会是这样的吧. 同理还有一个没法解释情况是,我们清空文件时,比如">linuxsir.cn" shell都做了什么,它是怎么做到的呢?(貌似很神秘喔^_^)


好了, 不管上述的结论是否成立, 如果用上述我所说的结论来解释类似这样的过程就很容易了:
  1. exec 1>linuxsir.cn
复制代码
就是上述(ii)中的过程,不过这里直接调用exec,也就是说把当前进程重定向了.
  1. exec 6>&1
复制代码
这里我们可以把&看做是C语言里的取地址操作,也就是说"&1"是个指针表达式,它是让文件描述符6系统文件表的指针改指向打开linuxsir.cn对应的系统文件表,这样做的结果就是将STDOUT给备份到文件描述符6,如果我们想恢复就是相反的过程: exec 1>&6.(当然别忘记关闭6:"exec 6>&-")
  1. exec 3<&0
复制代码
同理这里是备份STDIN.

OK, 能想到的也就这些了,可能是有错误的.希望大家批评指正,我也就能纠正下错误概念了.^_^

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
发表于 2007-11-22 19:50:19 | 显示全部楼层
Thanks! Hope we could see more like this!
回复 支持 反对

使用道具 举报

发表于 2007-11-23 09:27:40 | 显示全部楼层
to:  adamzyg
Congratulations!!! :Coffee:
百贴一精.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-11-23 09:43:25 | 显示全部楼层
嘿嘿,共勉!今天应该好好吃一顿补补身子!
回复 支持 反对

使用道具 举报

发表于 2007-12-3 14:01:32 | 显示全部楼层
好文章,支持一下!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表