Linux中文件描述符与FILE结构体

来源:互联网 发布:淘宝客服这工作怎么样 编辑:程序博客网 时间:2024/05/15 23:48

文件描述符

  我们知道在Linux系统中一切皆文件,文件的类型也是多种多样的,有普通文件,目录文件,链接文件。而当系统需要调用文件时,又是如何进行操作的,而文件描述符就是因此而诞生的,文件描述符(file descriptor)是内核为了高效管理已被打开的文件创建的索引。文件描述符的操作返回的是一个文件描述符,内核会在每个进程空间中维护一个文件描述表,所有打开的文件都将通过此表中的文件描述符来引用。
  这里写图片描述
  fd通常是一个非负整数。用于指代被打开的文件,可以将其想象成为一个数组,fd则是数组的下标,而数组中的内容则是所代表的文件索引。所有执行I/O操作的系统调用都通过文件描述符。程序刚刚启动的时候,我们查看文件描述符会发现其返回值是3,这是因为程序刚刚启动的时候,0是标准输入,1是标准输出,2是标准错误。文件描述符0理解为我和计算机交互时的输入,而这个输入默认是指向键盘的; 文件描述符1理解为我和计算机交互时的输出,而这个输出默认是指向显示器的; 文件描述符2理解为我和计算机交互时,计算机出现错误时的输出,而这个输出默认是和文件描述符1指向一个位置;如果此时去打开一个新的文件,它的文件描述符会是3.POSIX标准要求每次打开文件时必须使用当前进程中最小可用的文件描述号码,因此,在网络通信过程中稍不注意就有可能造成串话,我们的通道就是利用其来进行操作的。

文件描述符与FILE结构

  fd只是一个整数,在open时产生。起到一个索引的作用,进程通过PCB中的文件描述符表找到该fd所指向的文件指针filp。文件描述符的操作(如: open)返回的是一个文件描述符,内核会在每个进程空间中维护一个文件描述符表, 所有打开的文件都将通过此表中的文件描述符来引用;
而流(如: fopen)返回的是一个FILE结构指针, FILE结构是包含有文件描述符的,FILE结构函数可以看作是对fd直接操作的系统调用的封装, 它的优点是带有I/O缓存

FILE结构体详解

  文件结构体代表一个打开的文件,系统中的每个打开的文件在内核空间都有一个关联的 struct file。它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数。在文件的所有实例都关闭后,内核释放这个数据结构。在内核创建和驱动源码中,struct file的指针通常被命名为file或filp。我们可以在系统文件中找到其完整的结构体定义。
  file 结构如下所示:
  struct file {
  union {
  struct list_head fu_list; 文件对象链表指针linux/include/linux/list.h
  struct rcu_head fu_rcuhead; RCU(Read-Copy Update)是Linux 2.6内核中新的锁机制
  } f_u;
  struct path f_path; 包含dentry和mnt两个成员,用于确定文件路径
  #define f_dentry f_path.dentry f_path的成员之一,当前文件的dentry结构
  #define f_vfsmnt f_path.mnt 表示当前文件所在文件系统的挂载根目录
  const struct file_operations *f_op; 与该文件相关联的操作函数
  atomic_t f_count; 文件的引用计数(有多少进程打开该文件)
  unsigned int f_flags; 对应于open时指定的flag
  mode_t f_mode; 读写模式:open的mod_t mode参数
  off_t f_pos; 该文件在当前进程中的文件偏移量
  struct fown_struct f_owner; 该结构的作用是通过信号进行I/O时间通知的数据。
  unsigned int f_uid, f_gid; 文件所有者id,所有者组id
  struct file_ra_state f_ra; 在linux/include/linux/fs.h中定义,文件预读相关
  unsigned long f_version;
  #ifdef CONFIG_SECURITY
  void *f_security;
  #endif
  
  void *private_data;
  #ifdef CONFIG_EPOLL
  
  struct list_head f_ep_links;
  spinlock_t f_ep_lock;
  #endif
  struct address_space *f_mapping;
  };
  在其中,有一些结构体是其中一些需要我们注意的例如:
  1.mode_t f_mode;
文件模式确定文件是可读的或者是可写的(或者都是), 通过位 FMODE_READ 和FMODE_WRITE. 你可能想在你的 open 或者 ioctl 函数中检查这个成员的读写许可, 但是不需要检查读写许可, 因为内核在调用你的方法之前检查. 当文件还没有为那种存取而打开时读或写的企图被拒绝, 驱动甚至不知道这个情况.
2.loff_t f_pos;
当前读写位置. loff_t 在所有平台都是 64 位( 在 gcc 术语里是 long long ). 驱动可以读这个值,如果它需要知道文件中的当前位置, 但是正常地不应该改变它; 读和写应当使用它们作为最后参数而收到的指针来更新一个位置, 代替直接作用于 filp->f_pos. 这个规则的一个例外是在 llseek 方法中, 它的目的就是改变文件位置.
3.unsigned int f_flags;
这些是文件标志, 例如 O_RDONLY, O_NONBLOCK, 和 O_SYNC. 驱动应当检查O_NONBLOCK 标志来看是否是请求非阻塞操作; 其他标志很少使用. 特别地, 应当检查读/写许可, 使用 f_mode 而不是f_flags. 所有的标志在头文件

0 0