简单来说
就是一个非负整数,用以标明每一个被进程所打开的文件和socket,表示一个指向文件的引用。
维基百科
文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于Unix、Linux这样的操作系统。
默认分配的文件描述符
启动一个进程就会有有一个对应的虚拟地址空间,虚拟地址空间分成了内核区与用户区。
- 内核区:所有进程的内核区通过CPU 中的内存管理单元 MMU(Memory Management Unit)会将虚拟地址映射到同一块物理内存(内核只有一个),而且不允许不允许应用程序读写该区域的内容或直接调用内核代码定义的函数。+ 用户区:存储应用程序的数据,比如堆区(new),栈区(非静态变量等)等。
启动一个进程之后,内核 PCB 的文件描述符表中就已经分配了三个文件描述符。默认支持打开的最大文件数为 1024。
三个针对控制台Console标准流,0、1、2,都可以通过close()函数来关闭:
- STDIN_FILENO:标准输入,可以通过这个文件描述符将数据输入到终端文件中,宏值为 0。+ STDOUT_FILENO:标准输出,可以通过这个文件描述符将数据通过终端输出出来,宏值为 1。+ STDERR_FILENO:标准错误,可以通过这个文件描述符将错误信息通过终端输出出来,宏值为 2。
因此,这个进程给新打开的文件的文件描述符是从3,开始增长的。
优点
Linux、Unix的大部分系统调用都是基于文件描述符(window是基于句柄)。
缺点
当一个进程系统调用过多的时候,此时的文件描述符可能会不够用,可能会出现bug“Too many open files”,这样这个进程就会消耗完所有的文件资源,这时还需要一个限制,就是最大打开文件数。这个是文件描述符的系统级限制,可以使用sysctl命令或在proc文件系统中查看,表示所有用户能够打开的文件描述符的总和,还有一个是用户级限制,使用命令ulimit查看。
与文件描述符的产生相关的操作
socket(), open(), pipe(), read(), write(), recv(), send(), select(), poll(), epoll(),
与套接字相关的操作,socket是什么?套接字是什么?
- connect()+ bind()+ listen()+ accept()+ getsockname()+ getpeername()+ getsockopt(), setsockopt()+ shutdown()
三个命令查看文件描述符
系统级:
sysctl -a | grep -i file-max --clolr
cat /proc/sys/fs/file-max
用户级:
ulimit -n