(1).文件描述符的定义

  文件描述符是内核为了高效管理已被打开的文件所创建的索引,用于指向被打开的文件,所有执行I/O操作的系统调用都通过文件描述符;文件描述符是一个简单的非负整数,用以表明每个被进程打开的文件。程序刚刚启动时,第一个打开的文件是0,第二个是1,以此类推。也可以理解为文件的身份ID。

  用户通过操作系统处理信息的过程中,使用的交互设备文件(键盘,鼠标,显示器)

文件描述符

通道名

描述

默认连接

用途

0

stdin

标准输入

键盘

read only

1

stdout

标准输出

终端

write only

2

stderr

标准错误

终端

write only

3以上

filename

其他文件

none

read and/or write

标准输入输出说明

stdin,标准输入,默认设备是键盘,文件编号为0

stdout,标准输出,默认设备是显示器,文件编号为1,也可以重定向到文件

stderr,标准错误,默认设备是显示器,文件编号为2,也可以重定向到文件

(2).查看一个进程打开了哪些文件

语法: ll /proc/[进程ID]/fd

[xf@xuexi ~]$ vim a.txt 

[1]+  已停止               vim a.txt
[xf@xuexi ~]$ ps -aux | grep vim
xf        11990  0.6  0.2 151796  5396 pts/0    T    16:37   0:00 vim a.txt
xf        11998  0.0  0.0 112724   988 pts/0    S+   16:37   0:00 grep --color=auto vim
[xf@xuexi ~]$ ll /proc/11990/fd
总用量 0
lrwx------. 1 xf xf 64 2月  21 16:37 0 -> /dev/pts/0
lrwx------. 1 xf xf 64 2月  21 16:37 1 -> /dev/pts/0
lrwx------. 1 xf xf 64 2月  21 16:37 2 -> /dev/pts/0
lrwx------. 1 xf xf 64 2月  21 16:37 4 -> /home/xf/.a.txt.swp

  0、1、2也就是宏STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO。

  /proc/[进程ID]/fd这个目录专门用于存放文件描述符

  另外还可以使用ls -l /proc/self/fd。

(3).文件描述符限制

  Linux中最大文件描述符的限制有两个方面,一个是用户级限制,一个是系统级限制。

  但是,查看Linux文件描述符限制有三种方式:

[xf@xuexi ~]$ sysctl -a | grep file-max    //过滤一下,不然参数太多不好找
sysctl: permission denied on key 'fs.protected_hardlinks'
sysctl: permission denied on key 'fs.protected_symlinks'
fs.file-max = 196630    //file-max其实是红色字体
sysctl: permission denied on key 'kernel.cad_pid'
sysctl: permission denied on key 'kernel.usermodehelper.bset'
sysctl: permission denied on key 'kernel.usermodehelper.inheritable'
sysctl: permission denied on key 'net.core.bpf_jit_harden'
sysctl: permission denied on key 'net.ipv4.tcp_fastopen_key'
sysctl: permission denied on key 'net.ipv6.conf.all.stable_secret'
sysctl: permission denied on key 'net.ipv6.conf.default.stable_secret'
sysctl: permission denied on key 'net.ipv6.conf.ens33.stable_secret'
sysctl: permission denied on key 'net.ipv6.conf.lo.stable_secret'
sysctl: permission denied on key 'net.ipv6.conf.virbr0.stable_secret'
sysctl: permission denied on key 'net.ipv6.conf.virbr0-nic.stable_secret'
sysctl: permission denied on key 'vm.mmap_rnd_bits'
sysctl: permission denied on key 'vm.mmap_rnd_compat_bits'
[xf@xuexi ~]$ cat /proc/sys/fs/file-max 
196630
[xf@xuexi ~]$ ulimit -n
1024

  用户级限制:ulimit命令看到的是用户级的最大文件描述符限制,也就是说每一个用户登录后执行的程序占用文件描述符的总数不能超过这个限制

  系统级限制:sysctl命令与proc文件系统中查看到的数值是一样的,这属于系统级限制,它是限制所有用户打开文件描述符的总和。

1)修改用户级限制

临时修改上限,只对当前Shell有效

[xf@xuexi ~]$ ulimit -n  //-n打开文件描述符的最大个数
1024
[xf@xuexi ~]$ ulimit -Sn  //-S是软性限额
1024
[xf@xuexi ~]$ ulimit -Hn  //-H是硬性限额
4096
[xf@xuexi ~]$ ulimit -n 2048  //可以看到在没有指定-S和-H选项时修改会同时修改软性和硬性限额
[xf@xuexi ~]$ ulimit -n
2048
[xf@xuexi ~]$ ulimit -Sn
2048
[xf@xuexi ~]$ ulimit -Hn
2048
[xf@xuexi ~]$ ulimit -Hn 4096
bash: ulimit: open files: 无法修改 limit 值: 不允许的操作

注意:硬性限额在设置好不能增加,除非使用root用户;软性限额可以增加,直到与硬性限额相等。

永久修改需要使用root用户编辑/etc/security/limits.conf。里面会有详细说明。修改文件描述符,应该注意<item>字段下是否存在nofile字段,如果存在请修改,不存在请添加。

*    hard    nofile    4096
*    soft    nofile    2048

  添加完成后保存退出,重启系统,即可生效。

注意:soft一行中的<value>字段要小于或等于hard一行中的<value>字段。

2)修改系统限制级

  修改系统限制级,不管是临时修改还是永久修改都需要使用root用户。

  临时修改,重启后无效

//可以使用sysctl命令修改
[root@xuexi ~]# sysctl -w fs.file-max=8192
fs.file-max = 8192
[root@xuexi ~]# sysctl -a | grep fs.file-max
fs.file-max = 8192
sysctl: reading key "net.ipv6.conf.all.stable_secret"
sysctl: reading key "net.ipv6.conf.default.stable_secret"
sysctl: reading key "net.ipv6.conf.ens33.stable_secret"
sysctl: reading key "net.ipv6.conf.lo.stable_secret"
sysctl: reading key "net.ipv6.conf.virbr0.stable_secret"
sysctl: reading key "net.ipv6.conf.virbr0-nic.stable_secret"
[root@xuexi ~]# cat /proc/sys/fs/file-max 
8192
//也可以修改/proc/sys/fs/file-max文件
[root@xuexi ~]# cat >/proc/sys/fs/file-max <<EOF
> 16384
> EOF
[root@xuexi ~]# cat /proc/sys/fs/file-max 
16384
[root@xuexi ~]# sysctl -a | grep fs.file-max
fs.file-max = 16384
sysctl: reading key "net.ipv6.conf.all.stable_secret"
sysctl: reading key "net.ipv6.conf.default.stable_secret"
sysctl: reading key "net.ipv6.conf.ens33.stable_secret"
sysctl: reading key "net.ipv6.conf.lo.stable_secret"
sysctl: reading key "net.ipv6.conf.virbr0.stable_secret"
sysctl: reading key "net.ipv6.conf.virbr0-nic.stable_secret"

  永久修改需要进入到/etc/sysctl.conf中,修改或添加fs.file-max=value,然后重启系统或使用sysctl -p重新读取参数。

[root@xuexi ~]# vim /etc/sysctl.conf
[root@xuexi ~]# sysctl -a | grep fs.file-max
fs.file-max = 196630
sysctl: reading key "net.ipv6.conf.all.stable_secret"
sysctl: reading key "net.ipv6.conf.default.stable_secret"
sysctl: reading key "net.ipv6.conf.ens33.stable_secret"
sysctl: reading key "net.ipv6.conf.lo.stable_secret"
sysctl: reading key "net.ipv6.conf.virbr0.stable_secret"
sysctl: reading key "net.ipv6.conf.virbr0-nic.stable_secret"
[root@xuexi ~]# sysctl -p
fs.file-max = 10000
[root@xuexi ~]# sysctl -a | grep fs.file-max
fs.file-max = 10000
sysctl: reading key "net.ipv6.conf.all.stable_secret"
sysctl: reading key "net.ipv6.conf.default.stable_secret"
sysctl: reading key "net.ipv6.conf.ens33.stable_secret"
sysctl: reading key "net.ipv6.conf.lo.stable_secret"
sysctl: reading key "net.ipv6.conf.virbr0.stable_secret"
sysctl: reading key "net.ipv6.conf.virbr0-nic.stable_secret"

注:有些人说root用户使用命令sysctl -w fs.file-max=10000,接着sysctl -p就可永久修改。可是我试下来重启系统后就会还原,有时间的可以试一下。