第3章 文件IO | 001 文件描述符

  1. 概述

在Linux系统中一切皆可以看成是文件,文件又可分为:普通文件、目录文件、链接文件和设备文件。文件描述符(file descriptor)是内核为了高效管理已被打开的文件所创建的索引,其是一个非负整数(通常是小整数),用于指代被打开的文件,所有执行I/O操作的系统调用都通过文件描述符。程序刚刚启动的时候,0是标准输入,1是标准输出,2是标准错误。如果此时去打开一个新的文件,它的文件描述符会是3。 POSIX标准要求每次打开文件时(含socket)必须使用当前进程中最小可用的文件描述符号码,因此,在网络通信过程中稍不注意就有可能造成串话。 标准文件描述符图如下:
这里写图片描述

文件描述与打开的文件对应模型如下图:
这里写图片描述


  1. 文件描述限制

在编写文件操作的或者网络通信的软件时,初学者一般可能会遇到“Too many open files”的问题。这主要是因为文件描述符是系统的一个重要资源,虽然说系统内存有多少就可以打开多少的文件描述符,但是在实际实现过程中内核是会做相应的处理的,一般最大打开文件数会是系统内存的10%(以KB来计算)(称之为系统级限制),查看系统级别的最大打开文件数可以使用sysctl -a | grep fs.file-max命令查看。与此同时,内核为了不让某一个进程消耗掉所有的文件资源,其也会对单个进程最大打开文件数做默认值处理(称之为用户级限制),默认值一般是1024,使用ulimit -n命令可以查看。在Web服务器中,通过更改系统默认值文件描述符的最大值来优化服务器是最常见的方式之一。


  1. 文件描述符合打开文件之间的关系

每一个文件描述符会与一个打开文件相对应,同时,不同的文件描述符也会指向同一个文件。相同的文件可以被不同的进程打开也可以在同一个进程中被多次打开。系统为每一个进程维护了一个文件描述符表,该表的值都是从0开始的,所以在不同的进程中你会看到相同的文件描述符,这种情况下相同文件描述符有可能指向同一个文件,也有可能指向不同的文件。具体情况要具体分析,要理解具体其概况如何,需要查看由内核维护的3个数据结构。

** 1. 进程级的文件描述符表 **

** 2. 系统级的打开文件描述符表 **

** 3. 文件系统的i-node表 **

进程级的描述符表的每一条目记录了单个文件描述符的相关信息。

  1. 控制文件描述符操作的一组标志。(目前,此类标志仅定义了一个,即close-on-exec标志)

  2. 对打开文件句柄的引用

内核对所有打开的文件的文件维护有一个系统级的描述符表格(open file description table)。有时,也称之为打开文件表(open file table),并将表格中各条目称为打开文件句柄(open file handle)。一个打开文件句柄存储了与一个打开文件相关的全部信息,如下所示:

  1. 当前文件偏移量(调用read()和write()时更新,或使用lseek()直接修改)

  2. 打开文件时所使用的状态标识(即,open()的flags参数)

  3. 文件访问模式(如调用open()时所设置的只读模式、只写模式或读写模式)

  4. 与信号驱动相关的设置

  5. 对该文件i-node对象的引用

  6. 文件类型(例如:常规文件、套接字或FIFO)和访问权限

  7. 一个指针,指向该文件所持有的锁列表

  8. 文件的各种属性,包括文件大小以及与不同类型操作相关的时间戳

下图展示了文件描述符、打开的文件句柄以及i-node之间的关系,图中,两个进程拥有诸多打开的文件描述符。
这里写图片描述


  1. 文件描述符复制

在进程A中,文件描述符1和文件描述符20都指向同一个打开文件描述体(标号23)。这很可能是通过调用dup()系列函数形成的。

文件描述符复制,在某些场景下非常有用,比如:标准输入/输出重定向。在shell下,完成这个操作非常简单,大部分人都会,但是极少人思考过背后的原理。

大概描述一下需要的几个步骤,以标准输出(文件描述符为1)重定向为例:

打开目标文件,返回文件描述符n;
关闭文件描述符1;
调用dup将文件描述符n复制到1;
关闭文件描述符n;


  1. 子进程继承文件描述符

进程A的文件描述符2和进程B的文件描述符2都指向同一个打开文件描述体(标号73)。这种情形很可能发生在调用fork()派生子进程之后,比如A调用fork()派生出B。这时,B作为子进程,从父进程A继承了文件描述符表,其中包括图中标明的文件描述符2。这就是子进程继承父进程打开的文件这句话的由来。

当然了,进程A通过Unix套接字将一个文件描述符传递给B也会出现类似的情形,但一般文件描述符数值是不一样的。同时为2要非常凑巧才发生。


  1. 总结

  1. 由于进程级文件描述符表的存在,不同的进程中会出现相同的文件描述符,它们可能指向同一个文件,也可能指向不同的文件

  2. 两个不同的文件描述符,若指向同一个打开文件句柄,将共享同一文件偏移量。因此,如果通过其中一个文件描述符来修改文件偏移量(由调用read()、write()或lseek()所致),那么从另一个描述符中也会观察到变化,无论这两个文件描述符是否属于不同进程,还是同一个进程,情况都是如此。

  3. 要获取和修改打开的文件标志(例如:O_APPEND、O_NONBLOCK和O_ASYNC),可执行fcntl()的F_GETFL和F_SETFL操作,其对作用域的约束与上一条颇为类似。

  4. 文件描述符标志(即,close-on-exec)为进程和文件描述符所私有。对这一标志的修改将不会影响同一进程或不同进程中的其他文件描述符


  1. 参考资料

  1. Linux中的文件描述符与打开文件之间的关系
  2. Linux文件描述符
     
     
#include"apue.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/times.h>
int main ()
{struct tms time_buf_head , time_buf_end ;long   tck = 0 ;clock_t time_head , time_end ;tck = sysconf (_SC_CLK_TCK);   time_head = times (& time_buf_head);  printf ("head_time is : %f \n ", time_head / (double )tck); //system ("./time_test.exe");system ("sleep 2" );   time_end = times ( & time_buf_end );  printf ("end_time is : %f \n ", time_end / (double )tck );printf ("user time is : %f \n ", ((time_buf_end . tms_utime - time_buf_head . tms_utime) /( double )tck));  printf ("systime time is : %f \n ", ((time_buf_end . tms_stime - time_buf_head . tms_stime) / (double )tck));printf ("child user time is : %f \n ", ((time_buf_end . tms_cutime - time_buf_head . tms_cutime) / (double )tck));printf ("child sys time is : %f \n ", ((time_buf_end . tms_cstime - time_buf_head . tms_cstime) / (double )tck));return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/385662.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java提取图片中的文字,深入分析

第一个暴击&#xff1a;Spring 上一份Spring的手绘思维脑图&#xff08;就像是个知识大纲总结&#xff09;&#xff0c;预览一下Spring的知识点&#xff0c;心里有个谱。不过这边我是采用的截图方式&#xff0c;为了把全部的内容都截取出来&#xff0c;所以整个就比较小&#…

java基础入门传智播客答案,GitHub已标星16k

选择 在现在这个浮躁而又拜金的社会&#xff0c;我相信很多人做技术并非出于热爱&#xff0c;只是被互联网的高薪吸引&#xff0c;毕竟技术岗位非常枯燥&#xff0c;不仅要面对奇奇怪怪的需求&#xff0c;还要不停的充实自己避免被淘汰。所以想要吃好技术这碗饭并不容易。 我…

java基础入门第二版二手,细节爆炸

一面&#xff1a;70分钟 突击电话面试 正思考着项目功能模块&#xff0c;阿里面试官打来了电话&#xff0c;开始了阿里一面。 阿里面试官自我介绍&#xff0c;介绍了5分钟左右&#xff0c;部门的情况&#xff0c;主要的业务 提问开始 会哪些操作系统 Linux会一点说一下操作指…

进程通讯:管道

管道&#xff0c;通常指无名管道&#xff0c;是 UNIX 系统IPC最古老的形式。 1、特点&#xff1a; 它是半双工的&#xff08;即数据只能在一个方向上流动&#xff09;&#xff0c;具有固定的读端和写端。它只能用于具有亲缘关系的进程之间的通信&#xff08;也是父子进程或者兄…

java基础入门答案谭晓芳,原理+实战讲解

One&#xff1a;JVM实践思维图&#xff08;完整版&#xff09; Two&#xff1a; 走近Java 概述 Java技术体系Java发展史Java虚拟机家族&#xff1a;&#xff08;Sun Classic/Exact VM、HotSpot VM、Mobile/Embedded VM、BEA JRockit/IBM J9 VM、BEA Liquid VM/Azul VM、Apache…

java基础常问面试题,面试必问

一、首先本职工作一定要做好做精 本人之前在干兼职的时候&#xff0c;也忽视过本职工作&#xff0c;从而导致自己落后平均技术水平&#xff0c;虽然之后迎头赶上&#xff0c;但这不能不算是个遗憾。前在接一些活的时候就感觉技术的重要性了&#xff0c;如果当年我技术再好些&a…

java基础教程哪个好,吐血整理

RabbitMQ&#xff1a; 优点&#xff1a;轻量&#xff0c;迅捷&#xff0c;容易部署和使用&#xff0c;拥有灵活的路由配置 缺点&#xff1a;性能和吞吐量较差&#xff0c;不易进行二次开发 RocketMQ&#xff1a; 优点&#xff1a;性能好&#xff0c;稳定可靠&#xff0c;有活…

java基础教程哪个好,面试必会

如何才可以进大厂&#xff1f; 答案其实也很简单&#xff0c;能力学历。不知道大家有没有发现&#xff0c;大厂的一些部门对于学历要求已经放低了&#xff0c;阿里的一些部门同样也招大专学历的程序员&#xff0c;当然肯定也是因为他的能力足够出色。 对于准备秋招的你来说&a…

java基础教程第三版耿祥义,后台开发JAVA岗

Java虚拟机内存模型 Java虚拟机内存模型中定义的访问操作与物理计算机处理的基本一致&#xff01; Java中通过多线程机制使得多个任务同时执行处理&#xff0c;所有的线程共享JVM内存区域main memory&#xff0c;而每个线程又单独的有自己的工作内存&#xff0c;当线程与内存区…

java基础案例教程黑马程序员案例答案,真香

掌握核心知识 1、90%几率面试被问&#xff0c;吃透原理&#xff0c;面试不慌&#xff08;Spring原理&#xff09; 2、大厂必问Redis&#xff0c;赶紧码起来&#xff08;Redis核心原理&#xff09; 3、MySQL从入门到实战都在这篇&#xff0c;面试笑谈优化 当然核心知识不止这三…

java基础的三个框架,进阶学习资料!

阿里巴巴一面 自我介绍这个就不说了&#xff0c;开头必问的说一下StringBuilder 和 StringBufferSpring bean加载&#xff0c;实例化的过程Spring AOP源码看过吗java内存模型说一下如果给你一个map&#xff0c;里面有很多很多对象&#xff0c;那么这个map存放在哪了解GC算法吗…

实验3 | 由遍历序列构造二叉树

二叉树构造定理&#xff1a; 定理7.1&#xff1a;任何n&#xff08;n>0&#xff09;个不同结点的二又树&#xff0c;都可由它的中序序列和先序序列唯一地确定。 定理7.2&#xff1a;任何n&#xff08;n&#xff1e;0&#xff09;个不同结点的二又树&#xff0c;都可由它的…

万字总结!java让字符串反转

Java基础 JDK 和 JRE 有什么区别&#xff1f; 和 equals 的区别是什么&#xff1f;两个对象的 hashCode()相同&#xff0c;则 equals()也一定为 true&#xff0c;对吗&#xff1f;final 在 java 中有什么作用&#xff1f;java 中的 Math.round(-1.5) 等于多少&#xff1f;Stri…

万字总结!springcloud分布式限流

正文 作为后端开发&#xff0c;日常操作数据库最常用的是写操作和读操作。读操作我们下边会讲&#xff0c;这个分类里我们主要来看看写操作时为什么会导致 SQL 变慢。 刷脏页 脏页的定义是这样的&#xff1a;内存数据页和磁盘数据页不一致时&#xff0c;那么称这个内存数据页…

万字长文!java读取json文件数据给对象

Java基础核心笔记总结 由于篇幅限制&#xff0c;我就只以截图展示目录内容以及部分笔记内容&#xff0c;获取完整版王者级核心宝典只需要点击点赞关注即可获取领取方式&#xff01; 在这个部分我们总结了Java的基础知识&#xff0c;涵盖了&#xff1a;概述、开发环境、开发环境…

三年Java开发,java基础常问面试题

一、首先本职工作一定要做好做精 本人之前在干兼职的时候&#xff0c;也忽视过本职工作&#xff0c;从而导致自己落后平均技术水平&#xff0c;虽然之后迎头赶上&#xff0c;但这不能不算是个遗憾。前在接一些活的时候就感觉技术的重要性了&#xff0c;如果当年我技术再好些&a…

三年Java开发,尚学堂java马士兵全套

基于 Servlet 容器的 Web MVC 身为 Java 开发者&#xff0c;对于 Spring 框架并不陌生。它起源于 2002 年、Rod Johnson 著作《Expert One-on-One J2EE Design and Development》中的 Interface 21 框架&#xff0c;到了 2004 年&#xff0c;推出 Spring 1.0&#xff0c;从 XM…

三年经验java工资,含爱奇艺,小米,腾讯,阿里

1、PTP模型 Point-to-Point&#xff0c;点对点通信模型。PTP是基于队列(Queue)的&#xff0c;一个队列可以有多个生产者&#xff0c;和多个消费者。消息服务器按照收到消息的先后顺序&#xff0c;将消息放到队列中。队列中的每一条消息&#xff0c;只能由一个消费者进行消费&a…

三面美团Java岗,java多线程匿名内部类

Part 1微服务架构设计概述 1.1 传统应用架构的问题 1.2 微服务架构是什么 1.3 微服务架构有哪些特点和挑战 1.4 如何搭建微服务架构 Part 2微服务开发框架 2.1 Spring Boot 是什么 2.2 如何使用Spring Boot框架 2.3 Spring Boot生产级特性 Part 3微服务网关 3.1 Node.js 是什…

函数signal

1. 函数signal #include <signal.h> void (*signal(int sig,void (*func)(int)))(int)typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); 分析&#xff1a; signal参数信号名&#xff0c;func的值是SIG_ING、SIG_DFL或接到…