Linux中的fd
起子
如果说系统学Linux,我其实没有这个经历,你问我xx环境在Linux内核某个发行版怎么配置,那我可能可以告诉你,但是你要问我很多kernel相关的内容,那我就不懂了。在之前的一篇美团面经里涉及到select、poll、epoll这三个方法,那这三个方法肯定就和fd离不开关系,但是当时不懂这个是什么,于是乎就先跑去把fd学了一下,那理所应当的就要写一个随笔记录一下了。
文件描述符的简单概念
我们可以把文件描述符当作是一个非负整数,本质上是一个索引值,在Linux中我们都知道,一切都可以看作是文件,细分有普通文件、目录文件、链接文件、设备文件。OS里我们都学过文件管理,如果我们每次想要操作A文件,都要去找哪个文件名字和A一致,就十分的浪费时间,所以我们有了index(索引)这个概念。Linux内核中规定每一个文件对应一个索引
上述的这些索引就是文件描述符,通常是一个非负整数,并且值较小,文件描述符被拿来指代打开的文件,所有执行I/O操作的系统调用都通过文件描述符来实现。按照规定,0是stdin(标准输入),1是stdout(标准输出),2是标准错误(stderr)。这就意味着我们打开一个新文件,文件描述符紧接着会是3,再打开一个就是4……以此类推
同样的,还会有一张表格存储这些文件描述符(不解释原因了,这个OS都共通的),内容为文件描述符(一个小整数)与其对应打开的文件的指针。
文件描述符的详细内容
实际上Linux内核为文件描述符维护了3个数据结构:
- 进程级别的文件描述符表
- 系统级别的打开文件描述符表
- 文件系统的i-node表
当一个进程启动后,内核会为其创建一个PCB,PCB内部有一张文件描述符表,记录着当前进程所有可用的文件描述符,也就是当前进程所有打开的文件。进程级别的文件描述符表每一条都记录着单个进程所使用的文件描述符相关信息。需要注意的是,进程之间是相互独立的(这个也不解释了吧,大家都清楚),所以A进程使用了文件描述符3,那么另一个进程也可以使用文件描述符3。另外的两张表,系统级别的打开文件描述符表,存储了每个打开文件的打开文件句柄。一个打开文件句柄存储了与一个打开文件相关的全部信息。
系统级别的打开文件描述符表:
- 当前文件偏移量(使用read()和write()时更新,或使用lseek()直接修改)
- 打开文件的标识(open()的flags参数)
- 文件访问模式(是只读、只写或者读写等模式)
- 信号驱动相关设置
- i-node表指针
文件系统的i-node表
- 文件类型(常规文件、套接字)和访问权限
- 指向该文件所持有的锁列表
- 文件的各种属性,如文件大小、不同类型操作相关的时间戳
- 在进程A中,文件描述符1和20都指向了同一个打开文件表项,出现这种情况的原因可能是通过调用dup(),dup2(),fcntl()或者对同一个文件多次调用了open()函数所造成的
- 进程A的文件描述符2和进程B的文件描述符2指向了同一个文件,出现这种情况的原因可能是通过调用fork()函数后出现(即A和B进程是父子关系),或者是不同的进程独自调用open()函数打开了同一个文件
- 进程A的描述符0和进程B的描述符3虽然指向了不同的打开文件表项,但是却指向了同一个i-node表项;出现这种情况的原因可能是两个进程各自对同一个文件调用open(),或者是同一个进程两次打开同一个文件
Linux实际举例
我们找一个安装有基于Linux内核发行版系统的机器,然后在终端输入使用vim foobar
随便打开一个文件
之后再开一个连接(终端),然后输入pidof vim
或者vim的pid,紧接着用ll /proc/$pid/fd
来查看vim进程所使用的文件描述符列表
如果之前没看过我的那篇vim工作原理,可能就会对除了前三个之外的文件描述符产生疑惑,那3和4这两个文件描述符是redis自身的原因,我们不讨论,只讨论因为vim所导致的编号为6的文件描述符。
/dev/pts是远程登录(telnet、ssh等)后创建的终端设备文件所在的目录。0是标准输入,1是标准输出,2是标准错误,这些统统指向标号为0的终端控制台。而vim打开的redis.conf,按道理来说应该是顺接着标号为4的套接字,紧接着用5作为文件描述符,但图中却是6。
这个原因同样在vim工作原理的博客中讲到,原因是因为vim会先打开源文件并且拷贝一份,之后关闭源文件再打开副本进行修改,当副本修改完选择保存,就用副本重命名覆盖原文件。所以打开源文件其实就是文件描述符5,之后文件描述符5被释放,查看的时候就剩下了.swp副本文件。
Linux中关于文件描述符的系统配置
(1)系统级别的限制
从理论上来说,计算机有多少内存,我们可以一直开文件,也就是一直能有文件描述符,但是实际上我们肯定实现不了这点,所以内核会进行相应的处理。一般来说最大打开文件数是系统内存的十分之一,这个配置文件在/proc/sys/fs/file-max中配置,除了查看这个文件内容外,还可以使用sysctl -a | gerp fs.file-max来进行查看
临时更改系统级别限制大小的方式为:使用命令sysctl -w fs.file-max-xxx
来临时更改
永久更改的方式就需要编辑/etc/sysctl.conf
文件,在文件的内容后添加fs.file-max=xxx,保存退出后使用sysctl -p
使命令生效
(2)用户级别限制
内核也会对单个进程所能打开的最大文件数进行限制,也就是用户级别的限制,32位系统一般默认为1024,而64位系统一般默认为65535,我们可以使用ulimit -n
命令查看
临时更改用户级别限制大小方式为:使用命令ulimit -SHn xxxx
进行修改
永久更改用户级别限制大小的方式为:vim编辑/etc/security/limits.conf
文件,将其中的hard nofile xxxx
和soft nofile xxxx
结语
到这里就讲完我目前的水平对文件描述符的理解了,当然实际上肯定是有差错并且深度还远远不够的,还是和之前的文章一样,如果之后学习到了更加正确并且深层次的内容,同样会更新在这里,或者是开一篇新帖。
感谢阅读。
标签:文件,vim,描述符,fd,Linux,进程,打开 From: https://www.cnblogs.com/appletree24/p/16760512.html