Linux 文件描述符

原创 2016年08月29日 21:46:57
  文件描述符

1  什么是文件描述符

     在C程序中,文件由文件指针或者文件描述符表示。ISO C的标准I/0库函数(fopen, fclose, fread, fwrite, fscanf, fprintf等)使用文件指针,UNIX的I/O函数(open, close, read, write, ioctl)使用文件描述符。下面重点来说下,文件描述符是如何工作的。

    文件描述符是一个非负整数,打开现存文件或者新建文件时,内核会返回一个文件描述符,用于指代被打开的文件,所有执行I/O操作的系统调用都通过文件描述符。进程刚刚启动的时候,0是标准输入,1是标准输出,2是标准错误。如果此时去打开一个新的文件,它的文件描述符会是3。

理解文件描述符 与 三个概念:
    
     文件描述符表:用户区的一部分,每个进程维护自己的文件描述符表。对于进程中每个打开的文件,文件描述符表中都包含它的一个条目。除非通过使用文件描述符的函数,否则程序无法对其进行访问。
    
     系统文件表: 系统级别的,为系统中所有的进程共享。对每个活动的 open ,都包含它的一个条目。 系统文件表中的每个条目都包含文件偏移量、访问模式(读/写/读-写),以及指向这个条目的文件描述符的条目的计数和。
       
     内存索引节点表: 对系统中每个活动的文件(被某个进程open了),内存中的索引节点表都包含一个条目。几个系统文件表条目可能对应于同一个内存索引结点表(不同进程打开同一个文件)。

      三个表的关系:
         
   

             
 
      
     系统文件表包含一个偏移量,给出了某个进程操作文件当前的位置。每个进程都有它自己对该文件的当前偏移量。例如,若2个进程同时打开一个文件做读操作,每个进程都有自己相对于文件的偏移量,而且读入整个文件是独立于另一个进程的;如果2个进程打开同一个文件做写操作,写操作是相互独立的,每个进程都可以重写另一个进程写入的内容。
      
   文件描述符表中的每一项指向系统文件表。
   系统文件表被所有的进程共享,处于内核区,它与内存中的索引节点表对应。这样,进程通过对文件描述符表的操作,访问被内存中的索引节点表控制的文件。

 2、文件描述符的继承

通过fork()创建子进程时,子进程继承父进程环境和上下文的大部分内容的拷贝,其中就包括文件描述符表。 


 (1)对于父进程在fork()之前打开的文件来说,子进程都会继承,与父进程共享相同的文件偏移量。如下图所示(0-1-2 表示 标准输入-输出-错误) 
              
                                       
                                                       图2 fork()之前打开my.dat
 
        系统文件表位于系统空间中,不会被fork()复制,但是系统文件表中的条目会保存指向它的文件描述符表的计数,fork()时需要对这个计数进行维护,以体现子进程对应的新的文件描述符表也指向它。程序关闭文件时,也是将系统文件表条目内部的计数减一,当计数值减为0时,才将其删除。
 



(2)相反,如果父进程先进程fork,再打开my.dat,这时父子进程关于my.dat 的文件描述符表指向不同的系统文件表条目,也不再共享文件偏移量(fork以后2个进程分别open,在系统文件表中创建2个条目);但是关于标准输入,标准输出,标准错误,父子进程还是共享的。 

                                
                      图3   fork()以后打开my.dat




3. 文件描述限制
    
         在编写文件操作的或者网络通信的软件时,初学者一般可能会遇到“Too many open files”的问题。这主要是因为文件描述符是系统的一个重要资源,虽然说系统内存有多少就可以打开多少的文件描述符,但是在实际实现过程中内核是会做相应的处理的,一般最大打开文件数会是系统内存的10%(以KB来计算)(称之为系统级限制),查看系统级别的最大打开文件数可以使用sysctl -a | grep fs.file-max 命令查看。  
        与此同时,内核为了不让某一个进程消耗掉所有的文件资源,其也会对单个进程最大打开文件数做默认值处理(称之为用户级限制),默认值一般是1024,使用 ulimit -n 命令可以查看。在Web服务器中,通过更改系统默认值文件描述符的最大值来优化服务器是最常见的方式之一,具体优化方式请查看http://blog.csdn.net/kumu_linux/article/details/7877770。

         


4. 文件描述符合打开文件之间的关系
 
    每一个文件描述符会与一个打开文件相对应,同时,不同的文件描述符也会指向同一个文件。相同的文件可以被不同的进程打开,也可以在同一个进程中被多次打开。 系统为每一个进程维护了一个文件描述符表,该表的值都是从0开始的,所以在不同的进程中你会看到相同的文件描述符,这种情况下相同文件描述符有可能指向同一个文件,也有可能指向不同的文件。具体情况要具体分析,要理解具体其概况如何,需要查看由内核维护的3个数据结构。
    1. 进程级的文件描述符表
    2. 系统级的系统文件表
    3. 内存索引节点表(i-node表)
 
 
下图展示了文件描述符、文件系统表(打开的文件句柄 ) 以 及  i-node之间的关系,图中,两个进程拥有诸多打开的文件描述符。
                     
                       


解释:
    在进程A中,文件描述符1和30都指向了同一个打开的文件句柄(标号23)。这可能是通过调用dup()、dup2()、fcntl()或者对同一个文件多次调用了open()函数而形成的。
     进程A的文件描述符2和进程B的文件描述符2都指向了同一个打开的文件句柄(标号73)。这种情形可能是在调用fork()后出现的(即,进程A、B是父子进程关系),或者当某进程通过UNIX域套接字将一个打开的文件描述符传递给另一个进程时,也会发生。
    此外,进程A的描述符0和进程B的描述符3分别指向不同的打开文件句柄,但这些句柄均指向i-node表的相同条目(1976),换言之,指向同一个文件。发生这种情况是因为每个进程各自对同一个文件发起了open()调用。同一个进程两次打开同一个文件,也会发生类似情况。

小结:
        由于进程级文件描述符表的存在,不同的进程中会出现相同的文件描述符,它们可能指向同一个文件,也可能指向不同的文件。


补充: 
  
   文件描述符对系统性能的影响:

      对于squid,因为squid 的工作方式,文件描述符的限制可能会极大的影响性能。当squid 用完所有的文件描述符后,它不能接收用户新的连接。也就是说,用完文件描述符导致拒绝服务。直到一部分当前请求完成,相应的文件和socket 被关闭,squid不能接收新请求。当squid发现文件描述符短缺时,它会发布警告。
 
对于Apache,当使用了很多虚拟主机,而每个主机又使用了不同的日志文件时,Apache可能会遭遇耗尽文件描述符(有时也称为file handles)的困境。 Apache使用的文件描述符总数如下:每个不同的错误日志文件一个、 每个其他日志文件指令一个、再加10~20个作为内部使用。Unix操作系统限制了每个进程可以使用的文件描述符数量。典型上限是64个,但可以进行扩充,直至到达一个很大的硬限制为止(a large hard-limit)。


Linux 对最大文件描述符数量的限制,表现在两方面: 用户级的限制和系统级的限制.

linux 下查看文件描述符的三种方式:
 
  1. [root@MyDB ~]# sysctl -a | grep -i file-max
  2. fs.file-max = 57389
  3. [root@MyDB ~]# cat /proc/sys/fs/file-max
  4. 57389
  5. [root@MyDB ~]# ulimit -n
  6. 1024

系统级限制:sysctl命令和 /proc/sys/fs/ 文件系统中查看到的数值是一样的,这属于系统级限制,它是限制所有用户打开文件描述符的总和
用户级限制: ulimit 命令看到的是用户级的最大文件描述符限制,也就是说每一个用户登录后执行的程序占用文件描述符的总数不能超过这个限制
 
同时,这一限制也可以针对某一个用户进程来进行限制,比如 mysql :
       
 
关于使用 ulimit 针对 系统、不同用户、不同进程 的 最大文件描述符的限制参见:http://blog.csdn.net/wanghai__/article/details/6332540 

下面是摘自kernel document中关于file-max和file-nr参数的说明
file-max & file-nr:
 
  1. The kernel allocates file handles dynamically, but as yet it doesn't free them again.
  2. 内核可以动态的分配文件句柄,但到目前为止是不会释放它们的
  3.  
  4. The value in file-max denotes the maximum number of file handles that the Linux kernel will allocate. When you get lots of error messages about running out of file handles, you might want to increase this limit.
  5. file-max的值是linux内核可以分配的最大文件句柄数。如果你看到了很多关于打开文件数已经达到了最大值的错误信息,你可以试着增加该值的限制
  6.  
  7. Historically, the three values in file-nr denoted the number of allocated file handles, the number of allocated but unused file handles, and the maximum number of file handles. Linux 2.6 always reports 0 as the number of free file handles -- this is not an error, it just means that the number of allocated file handles exactly matches the number of used file handles.
  8. kernel 2.6之前的版本中,file-nr 中的值由三部分组成,分别为:1.已经分配的文件句柄数,2.已经分配单没有使用的文件句柄数,3.最大文件句柄数。但在kernel 2.6版本中第二项的值总为0,这并不是一个错误,它实际上意味着已经分配的文件句柄无一浪费的都已经被使用了



参考:
http://blog.csdn.net/cywosp/article/details/38965239
http://www.cnblogs.com/FengGettingBetter/p/3357681.html 
http://blog.csdn.net/kumu_linux/article/details/7877770  






版权声明:本文为博主原创文章,转载请注明连接。

相关文章推荐

linux 定时任务详解 按秒设定

实现linux定时任务有:cron、anacron、at等,这里主要介绍cron服务。名词解释:   cron是服务名称,crond是后台进程,crontab则是定制好的计划任务表。软件包安装:要使用...

使用jstack和TDA进行java线程dump分析

直接查看jstack的输出文件分析,看起来可能看起来比较麻烦,尤其在线程多的情况下,使用TDA等工具可以降低分析的工作量。...

Linux查看进程打开多少文件描述符命令-lsof

转自:http://blog.csdn.net/zlzlei/article/details/7730253 lsof简介 lsof(list open files)是...

linux 文件描述符的一些底层实现

转载请说明出处:http://blog.csdn.net/cywosp/article/details/38965239 1. 概述     在Linux系统中一切皆可以看成是文件...

linux进程与它的文件描述符

一)概述 .open系统调用返回的文件描述符是非负整型. .每一个进程都有自己的文件描述符集合. .当创建进程时,通常有3个打开文件描述符(0,1,2),0代表标准输入,1代表标准输出,2代表标...

linux下文件描述符的介绍

当某个程序打开文件时,操作系统返回相应的文件描述符,程序为了处理该文件必须引用此描述符。所谓的文件描述符是一个低级的正整数。最前面的三个文件描述符(0,1,2)分别与标准输入(stdin),标准输出(...

【Linux&Unix--文件描述符与权限】

个人学习整理,如有不足之处,请不吝指教。转载请注明:@CSU-Max 文件描述符    每个UNIX进程都有一个文件描述符范围,其大小为0到N,N标志文件描述符的最大值,N的大小取决于UNI...
  • kana007
  • kana007
  • 2014年07月12日 10:46
  • 1152

linux学习——前期一些问题验证(文件描述符、线程)

开始全新系统的学习,又是 熟悉的hello world模式入门。公司项目逼得紧迫,都找不出时间开始系统的学习,以前看过linux方面的书籍早就忘的一干二净了,这几天看了实际代码,今天验证一些想法。首先...

Linux编程基础:文件描述符file descriptor与inode

每个进程在Linux内核中都有一个task_struct结构体来维护进程相关的 信息,称为进程描述符(Process Descriptor),而在操作系统理论中称为进程控制块 (PCB,Process...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux 文件描述符
举报原因:
原因补充:

(最多只允许输入30个字)