博文说明【前言】:
html
本文将经过我的口吻介绍经过Linux中的文件描述符相关知识,在目前时间点【2017年7月4号】下,所掌握的技术水平有限,可能会存在很多知识理解不够深刻或全面,望你们指出问题共同交流,在后续工做及学习中如发现本文内容与实际状况有所误差,将会完善该博文内容。node
本文参考文献引用连接:linux
一、http://www.cnblogs.com/reach296/p/3915512.htmlshell
二、http://blog.csdn.net/cywosp/article/details/38965239【这篇文章不错】 vim
三、http://blog.csdn.net/kumu_linux/article/details/7877770【好文】服务器
正文:网络
咱们知道,在Linux中,一切皆文件,其实这个文件也是分为好几类的。数据结构
主要有(以ls -l命令输出为例):socket
- #普通文件ide
d #目录文件
l #连接文件
c #设备文件中的-字符型设备文件
b #设备文件中的-块设备文件
n #设备文件中的-网络设备文件
一、普通文件
该文件是是用户平常使用最多的文件,包括文本文件、shell脚本、二进制的可执行和各类类型的数据文件等等。
该文件的属性一般是: -rw-r--r-- 这些文件通常是由一些相关的应用程序建立,好比touch,vim等
二、目录文件
在Linux中,目录也是文件,目录的内容可以是文件名和子目录名以及指向那些文件和子目录的指针
目录文件的属性一般是:drwxr-xr-x ,目录在Linux是一个比较特殊的文件。
三、连接文件
连接文件相似于Windows中的“快捷方式”
建立命令格式:
# ln/cp -s/-l /绝对路径/源文件名 /绝对路径/新文件名
建立命令有:
ln(建立硬连接,需在同一个文件系统中,inode号相同,删除源文件后连接文件依然存在)
ln -s(建立软连接,也就是符号连接,能够跨越文件系统,inode号不一样,删除源文件后连接文件失效)
cp -l(建立硬连接,需在同一个文件系统中,inode号相同,删除源文件后连接文件依然存在)
cp -s(建立软连接,也就是符号连接,能够跨越文件系统,inode号不一样,删除源文件后连接文件失效)
四、设备文件
包括三种,块设备文件,另外一种是字符设备文件,网络设备文件不怎么涉及。
字符设备(无缓冲且只能顺序存取)、块设备(有缓冲且能够随机存取)。
块设备文件是指数据的读写,它们是以块为单位的设备,如硬盘光驱。
字符设备主要是指串行端口的接口设备,如网卡等。
好了,基础概念介绍完毕,开始正题,上方为我的编写,下方为引用,因引用篇幅超过50%,因此本文视为转载。
问题1:什么是文件描述符?
1. 文件描述概念
文件描述符是一个简单的整数,用以标明每个被进程所打开的文件和socket。第一个打开的文件是0,第二个是1,第三个文件是2,依此类推。
文件描述符(file descriptor)是内核为了高效管理已被打开的文件所建立的索引,其是一个非负整数(一般是小整数),用于指代被打开的文件,全部执行I/O操做的系统调用都经过文件描述符。程序刚刚启动的时候,0是标准输入,1是标准输出,2是标准错误。若是此时去打开一个新的文件,它的文件描述符会是3。POSIX标准要求每次打开文件时(含socket)必须使用当前进程中最小可用的文件描述符号码,所以,在网络通讯过程当中稍不注意就有可能形成串话。标准文件描述符图以下:
文件描述与打开的文件对应模型以下图:
2. 文件描述限制
在编写文件操做的或者网络通讯的软件时,初学者通常可能会遇到“Too many open files”的问题。这主要是由于文件描述符是系统的一个重要资源,虽说系统内存有多少就能够打开多少的文件描述符,可是在实际实现过程当中内核是会作相应的处理的,通常最大打开文件数会是系统内存的10%(以KB来计算)(称之为系统级限制)
查看系统级别的最大打开文件数可使用该命令查看:sysctl -a | grep fs.file-max
与此同时,内核为了避免让某一个进程消耗掉全部的文件资源,其也会对单个进程最大打开文件数作默认值处理(称之为用户级限制),默认值通常是1024,使用ulimit -n命令能够查看。在Web服务器中,经过更改系统默认值文件描述符的最大值来优化服务器是最多见的方式之一。
3. 文件描述符合打开文件之间的关系
每个文件描述符会与一个打开文件相对应,同时,不一样的文件描述符也会指向同一个文件。相同的文件能够被不一样的进程打开也能够在同一个进程中被屡次打开。系统为每个进程维护了一个文件描述符表,该表的值都是从0开始的,因此在不一样的进程中你会看到相同的文件描述符,这种状况下相同文件描述符有可能指向同一个文件,也有可能指向不一样的文件。具体状况要具体分析,要理解具体其概况如何,须要查看由内核维护的3个数据结构。
1. 进程级的文件描述符表
2. 系统级的打开文件描述符表
3. 文件系统的i-node表
进程级的描述符表的每一条目记录了单个文件描述符的相关信息。
1. 控制文件描述符操做的一组标志。(目前,此类标志仅定义了一个,即close-on-exec标志)
2. 对打开文件句柄的引用
内核对全部打开的文件的文件维护有一个系统级的描述符表格(open file description table)。有时,也称之为打开文件表(open file table),并将表格中各条目称为打开文件句柄(open file handle)。一个打开文件句柄存储了与一个打开文件相关的所有信息,以下所示:
1. 当前文件偏移量(调用read()和write()时更新,或使用lseek()直接修改)
2. 打开文件时所使用的状态标识(即,open()的flags参数)
3. 文件访问模式(如调用open()时所设置的只读模式、只写模式或读写模式)
4. 与信号驱动相关的设置
5. 对该文件i-node对象的引用
6. 文件类型(例如:常规文件、套接字或FIFO)和访问权限
7. 一个指针,指向该文件所持有的锁列表
8. 文件的各类属性,包括文件大小以及与不一样类型操做相关的时间戳
下图展现了文件描述符、打开的文件句柄以及i-node之间的关系,图中,两个进程拥有诸多打开的文件描述符。
在进程A中,文件描述符1和30都指向了同一个打开的文件句柄(标号23)。这多是经过调用dup()、dup2()、fcntl()或者对同一个文件屡次调用了open()函数而造成的。
进程A的文件描述符2和进程B的文件描述符2都指向了同一个打开的文件句柄(标号73)。这种情形多是在调用fork()后出现的(即,进程A、B是父子进程关系),或者当某进程经过UNIX域套接字将一个打开的文件描述符传递给另外一个进程时,也会发生。再者是不一样的进程独自去调用open函数打开了同一个文件,此时进程内部的描述符正好分配到与其余进程打开该文件的描述符同样。
此外,进程A的描述符0和进程B的描述符3分别指向不一样的打开文件句柄,但这些句柄均指向i-node表的相同条目(1976),换言之,指向同一个文件。发生这种状况是由于每一个进程各自对同一个文件发起了open()调用。同一个进程两次打开同一个文件,也会发生相似状况。
4. 总结
1. 因为进程级文件描述符表的存在,不一样的进程中会出现相同的文件描述符,它们可能指向同一个文件,也可能指向不一样的文件
2. 两个不一样的文件描述符,若指向同一个打开文件句柄,将共享同一文件偏移量。所以,若是经过其中一个文件描述符来修改文件偏移量(由调用read()、write()或lseek()所致),那么从另外一个描述符中也会观察到变化,不管这两个文件描述符是否属于不一样进程,仍是同一个进程,状况都是如此。
3. 要获取和修改打开的文件标志(例如:O_APPEND、O_NONBLOCK和O_ASYNC),可执行fcntl()的F_GETFL和F_SETFL操做,其对做用域的约束与上一条颇为相似。
4. 文件描述符标志(即,close-on-exec)为进程和文件描述符所私有。对这一标志的修改将不会影响同一进程或不一样进程中的其余文件描述符
文件描述符的具体应用
对于squid,由于squid 的工做方式,文件描述符的限制可能会极大的影响性能。当squid 用完全部的文件描述符后,它不能接收用户新的链接。也就是说,用完文件描述符致使拒绝服务。直到一部分当前请求完成,相应的文件和socket 被关闭,squid不能接收新请求。当squid发现文件描述符短缺时,它会发布警告。
对于Apache,当使用了不少虚拟主机,而每一个主机又使用了不一样的日志文件时,Apache可能会遭遇耗尽文件描述符(有时也称为file handles)的困境。 Apache使用的文件描述符总数以下:每一个不一样的错误日志文件一个、 每一个其余日志文件指令一个、再加10~20个做为内部使用。Unix操做系统限制了每一个进程可使用的文件描述符数量。典型上限是64个,但能够进行扩充,直至到达一个很大的硬限制为止(a large hard-limit)。
linux下最大文件描述符的限制有两个方面,一个是用户级的限制,另一个则是系统级限制。
如下是查看Linux文件描述符的三种方式:
系统级限制:
[root@localhost ~]# sysctl -a | grep -i file-max --color
fs.file-max = 392036
[root@localhost ~]# cat /proc/sys/fs/file-max
392036
用户级限制:
[root@localhost ~]# ulimit -n
1024
[root@localhost ~]#
系统级限制:sysctl命令和proc文件系统中查看到的数值是同样的,这属于系统级限制,它是限制全部用户打开文件描述符的总和
用户级限制:ulimit命令看到的是用户级的最大文件描述符限制,也就是说每个用户登陆后执行的程序占用文件描述符的总数不能超过这个限制
如何修改文件描述符的值?
一、修改用户级限制
[root@localhost ~]# ulimit-SHn 10240
[root@localhost ~]# ulimit -n
10240
[root@localhost ~]#
以上的修改只对当前会话起做用,是临时性的,若是须要永久修改,则要修改以下:
[root@localhost ~]# grep -vE'^$|^#' /etc/security/limits.conf
* hard nofile 4096
[root@localhost ~]#
//默认配置文件中只有hard选项,soft 指的是当前系统生效的设置值,hard 代表系统中所能设定的最大值
[root@localhost ~]# grep -vE'^$|^#' /etc/security/limits.conf
* hard nofile 10240
* soft nofile 10240
[root@localhost ~]#
// soft<=hard soft的限制不能比hard限制高
二、修改系统限制
[root@localhost ~]# sysctl -wfs.file-max=400000
fs.file-max = 400000
[root@localhost ~]# echo350000 > /proc/sys/fs/file-max //重启后失效
[root@localhost ~]# cat /proc/sys/fs/file-max
350000
[root@localhost ~]#
//以上是临时修改文件描述符
//永久修改把fs.file-max=400000添加到/etc/sysctl.conf中,使用sysctl -p便可
下面是摘自kernel document中关于file-max和file-nr参数的说明
file-max & file-nr:
The kernel allocates file handles dynamically, but as yet it doesn't free them again.
内核能够动态的分配文件句柄,但到目前为止是不会释放它们的
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.
file-max的值是linux内核能够分配的最大文件句柄数。若是你看到了不少关于打开文件数已经达到了最大值的错误信息,你能够试着增长该值的限制
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.
在kernel 2.6以前的版本中,file-nr 中的值由三部分组成,分别为:1.已经分配的文件句柄数,2.已经分配单没有使用的文件句柄数,3.最大文件句柄数。但在kernel 2.6版本中第二项的值总为0,这并非一个错误,它实际上意味着已经分配的文件句柄无一浪费的都已经被使用了
结尾:
感谢阅读,祝有收获的一天,谢谢!