文件描述符

56 篇文章 1 订阅

一、什么是文件描述符?
在linux下一切皆文件,文件描述符是内核为了高效的管理已经被打开的文件所创建的索引,它是一个非负整数,用于指代被打开的文件,所有执行I/O操作的系统调用都是通过文件描述符完成的。
在linux中,进程是通过文件描述符(file descriptors 简称fd)来访问文件的,文件描述符实际上是一个整数。在程序刚启动的时候,默认有三个文件描述符,分别是:0(代表标准输入),1(代表标准输出),2(代表标准错误)。再打开一个新的文件的话,它的文件描述符就是3。
POSIX标准规定,每次打开的文件时(含socket)必须使用当前进程中最小可用的文件描述符号码。
试想一下,如我们将0号文件描述符关闭,然后打开一个文件file,则file的文件描述符就是0,这代表了标准输入。也就是说我们如果向标准输出流输出的话,就会输出到这个文件里面。这不跟重定向很像吗?当然重定向肯定比这个更加的复杂。

二、如何创建文件描述符
进程获取文件描述符最常见的方法就是通过系统函数open或create获取,或者是从父进程继承。
从父进程继承的话,子进程就可以访问父进程所使用的文件。我们再深入想想,进程是独立运行的,互不干扰,如果父子进程要通信的话,是不是就可以通过这些都能访问的文件入手。
文件描述符对于每一个进程是唯一的,每个进程都有一张文件描述符表,用于管理文件描述符。当使用fork创建子进程的话,子进程会获得父进程所有文件描述符的副本,这些文件描述符在执行fork时打开。在由fcntl、dup和dup2子例程复制或拷贝某个进程时,会发生同样的复制过程。

三、文件描述符与打开文件之间的关系
每一个文件描述符都与一个打开的文件相对应,同时,不同的文件描述符也会指向同一个文件。相同的文件可以被不同的进程打开,也可以在同一个进程中被打开多次。系统为每一个进程维护了一个文件描述符表,该表的值从0开始,所以在不同的进程中会看到相同的文件描述符,这种情况下的相同的文件描述符有可能指向同一个文件,也有可能指向不同的文件。
内核维护了三种文件描述符表:
1、进程级别的文件描述符表。
进程级别的文件描述符表的每一条目都记录了单个文件描述符的相关信息。表里面的信息分别是:控制文件描述符操作的一组标志、对打开文件句柄的引用。这个进程级别的文件描述符表用files_struct结构表示,在PCB中有一个这个结构类型的指针变量files。
files_struct定义如下:

struct files_struct {
atomic_t count; /* 共享该表的进程数 */
rwlock_t file_lock; /* 保护以下的所有域,以免在tsk->alloc_lock中的嵌套*/
int max_fds; /*当前文件对象的最大数*/
int max_fdset; /*当前文件描述符的最大数*/
    int next_fd; /*已分配的文件描述符加1*/
struct file ** fd; /* 指向文件对象指针数组的指针 */
fd_set *close_on_exec; /*指向执行exec( )时需要关闭的文件描述符*/
fd_set *open_fds; /*指向打开文件描述符的指针*/
fd_set close_on_exec_init;/* 执行exec( )时需要关闭的文件描述符的初 值集合*/
        fd_set open_fds_init; /*文件描述符的初值集合*/
struct file * fd_array[32];/* 文件对象指针的初始化数组*/
};

2、系统级别的文件描述符表。
内核对所有打开的文件有一个系统级别的文件描述符表。有时也称为打开文件描述符表,并将表格中各条目称为打开文件句柄。一个打开文件句柄存储了这个打开文件的全部相关信息。
大致包含以下信息:
1、当前文件偏移量
2、打开文件时所使用的状态标识(open中的flags参数)
3、文件访问模式(只读,只写,读写模式)
4、与信号驱动相关的设置。
5、对该文件的i-node引用。
6、文件类型和访问权限。
7、一个指针、指向该文件所持有的锁列表。
8、文件的各种属性,包括文件大小及不同类型操作相关的时间戳。

相关定义:

struct file
{
struct list_head f_list; /*所有打开的文件形成一个链表*/
struct dentry *f_dentry; /*指向相关目录项的指针*/
struct vfsmount *f_vfsmnt; /*指向VFS安装点的指针*/
struct file_operations *f_op; /*指向文件操作表的指针*/
mode_t f_mode; /*文件的打开模式*/
loff_t f_pos; /*文件的当前位置*/
unsigned short f_flags; /*打开文件时所指定的标志*/
unsigned short f_count; /*使用该结构的进程数*/
unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
/*预读标志、要预读的最多页面数、上次预读后的文件指针、预读的字节数以及
预读的页面数*/
int f_owner; /* 通过信号进行异步I/O数据的传送*/
unsigned int f_uid, f_gid; /*用户的UID和GID*/
int f_error; /*网络写操作的错误码*/

unsigned long f_version; /*版本号*/
void *private_data; /* tty驱动程序所需 */

};

3、文件系统的i-node表。
保存了文件系统的相关信息。

这里写图片描述

四 、文件描述符的限制
linux下最大文件描述符的限制有两个方面,一个是用户级限制,另一个是系统级限制。他们限制了进程能够打开文件的数量。

4.1、系统级限制
因为文件描述符是系统的一个重要资源,所以在实际过程中内核会对打开文件数做一个限制。这就叫做系统级限制。
命令:sysctl -a | grep fs.file-max 可以查看当前的系统级限制能够打开的最大文件数。
这里写图片描述

修改:通过 sysctl -w fs.file-max=文件数 命令修改。
但是使用sysctl命令修改是临时性的,如果要永久的改变,局需要在 /etc/sysctl.conf 中添加 fs.file-max=文件数 退出后并保存,使用sysctl -p命令使其生效。
这里写图片描述

4.2、用户级限制
内核为了不让某一个进程消耗掉所有的文件资源,会对单个进程打开文件数做默认处理,这就称为用户级限制。
命令:ulimit -n 可以查看当前用户级限制下进程能打开的文件最大的个数。
这里写图片描述
可以看到,单个进程最多有1024个文件描述符。

修改:ulimit -SHn 文件数 可以修改用户级限制。
这里写图片描述
同样,这个命令修改也是临时的,要想一劳永逸,就必须修改/etc/security/limits.conf配置文件。
在该文件里面添加:
hard nofile 文件数
soft nofile 文件数
然后保存退出重新登录,就可以了。

五、文件描述符与文件指针的区别
文件描述符:在linux系统中打开文件就会获得文件描述符,它是一个很小的整数。每个进程控制块(PCB)中保存着一份文件描述符表,文件描述符就是文件描述符表的索引,每个表项都有一个指向打开文件的文件指针,这个文件指针指向进程用户区中的一个被称为FILE的数据结构。FILE结构包含一个缓冲区和一个文件描述符。而文件描述符是文件描述符表的一个索引,因此从某些意义上来说,文件指针就是文件描述符的句柄。

六、基于文件描述符的输入输出函数
open:以指定方式打开一个文件,调用成功后返回一个文件描述符。
creat:打开一个文件,如果文件不存在则创建它,成功后返回一个文件描述符。
close:关闭文件,进程对文件加锁全部被释放。
read:从文件描述符对应的文件中读取文件,成功后返回读出的字节数。
write:向文件描述符对应的文件中写入数据,成功后返回写入的字节数。
ftruncate:把文件描述符对应的文件缩短到指定的长度。
lseek:把文件指针设置到指定的位置,相当于库函数中的fseek。
fsync:将已经写入到文件的数据写入到磁盘或其他下层设备中,成功返回0。
fstat:返回文件描述符所对应文件的相关信息,把结果保存在struct stat中,成功返回0。
fchown:修改文件描述符对应的文件的文件所有者和文件所有者组的信息。
fchmod:修改文件描述符对应的文件的权限。
flock:对文件施加建议性锁,成功返回0。
fcntl:技能施加建议性锁也能施加强制性锁,能建立记录锁、读取锁,写入锁,成功返回0
dup:复制文件描述符,返回没有使用的文件描述符中的最小编号。
dup2:由用户指定返回的文件描述符的值,用来重新打开或重定向一个文件描述符。
select:同时从多个文件描述符读取数据或向多个文件描述符写入数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值