嵌入式Linux系统编程 — 1.5 文件描述符详解

目录

1 文件描述符简介

1.1 文件描述符特点

1.2 标准文件描述符

1.3 文件描述符的生命周期

2 fcntl()函数

2.1 fcntl()函数简介

2.2 复制文件描述符(F_DUPFD)

2.3 获取/设置文件状态标志(F_GETFL/F_SETFL )


1 文件描述符简介

文件描述符(File Descriptor)是Linux和UNIX系统编程中的一个重要概念,它是一个用于标识打开文件或其他输入/输出资源的非负整数,文件描述符允许程序通过一个抽象的数字来引用文件和其他输入输出资源,而不是直接使用文件名或设备名。

从上面的示例代码中可以看到,调用 open 函数会有一个返回值, 譬如示例代码中的 fd1 和 fd2, 这是一个 int 类型的数据,在 open函数执行成功的情况下, 会返回一个非负整数, 该返回值就是一个文件描述符(file descriptor)。

1.1 文件描述符特点

  • 唯一性:每个打开的文件或设备在进程中都有一个唯一的文件描述符。文件描述符是从 3 开始分配的,譬如说进程中第一个被打开的文件对应的文件描述符是 3、第二个文件是 4……以此类推。为什么是从3开始?因为0、 1、 2 这三个文件描述符已经默认被系统占用了,分别分配给了系统标准输入(0)、 标准输出(1)以及标准错误(2)。

  • 抽象性:文件描述符提供了一个抽象层,使得对各种类型的输入输出设备的操作看起来像是对文件的操作。

  • 有限性:文件描述符的数量是有限的,通常由系统设置决定,例如Linux系统中可以通过ulimit -a 或 ulimit -a 命令查看文件描述符的限制。

该最大值默认情况下是 1024,也就意味着一个进程最多可以打开 1024 个文件,当然这个限制数其实是可以设置的。

1.2 标准文件描述符

在Linux中,每个进程启动时都会自动打开三个标准文件描述符:

  • 标准输入(stdin):文件描述符为0,通常用于从键盘接收输入。
  • 标准输出(stdout):文件描述符为1,通常用于向屏幕输出文本。
  • 标准错误(stderr):文件描述符为2,通常用于输出错误信息。

1.3 文件描述符的生命周期

  • 打开:使用open()openat()等系统调用打开文件时,系统会分配一个新的文件描述符。

  • 使用:通过文件描述符,可以使用read()write()lseek()等系统调用来读写数据或移动文件指针。

  • 关闭:使用close()系统调用关闭文件描述符,释放与该文件描述符关联的资源。

  • 重定向:可以将文件描述符重定向到其他文件描述符或文件,例如通过dup()dup2()

2 fcntl()函数

2.1 fcntl()函数简介

fcntl()函数可以对一个已经打开的文件描述符执行一系列控制操作,譬如复制一个文件描述符(与 dup、dup2 作用相同)、获取/设置文件描述符标志、获取/设置文件状态标志等,类似于一个多功能文件描述符管理工具箱。 fcntl()函数原型如下所示:

#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */ );

参数说明:

  • fd:文件描述符,即要控制的文件或设备的标识符。
  • cmd:控制命令,指定要执行的操作类型。
  • arg(可选):某些命令需要额外的参数,这些参数会通过arg传递给fcntl()

常见的控制命令(cmd):

  • F_DUPFD:复制文件描述符。如果提供了arg,则新文件描述符的最小值是arg,否则是当前进程的最大文件描述符加1。
  • F_GETFD:获取文件描述符的标志。FD_CLOEXEC:当执行exec系列函数时,关闭文件描述符;O_NONBLOCK:设置非阻塞模式;O_ASYNC:使文件描述符异步。
  • F_SETFD:设置文件描述符的标志。
  • F_GETFL:获取文件状态标志。
  • F_SETFL:设置文件状态标志。
  • F_GETLK:获取记录锁。
  • F_SETLK:设置记录锁。
  • F_SETLKW:等待直到可以设置记录锁。
  • F_GETOWN:获取文件描述符的所有者(通常用于异步I/O)。
  • F_SETOWN:设置文件描述符的所有者。

2.2 复制文件描述符(F_DUPFD)

dup 和 dup2用于复制文件描述符,除此之外,还可以通过 fcntl 函数复制文件描 述 符,可用的 cmd包括 F_DUPFD 和 F_DUPFD_CLOEXEC , 这里重点介绍 F_DUPFD 。

使用场景:使用 F_DUPFD 可以方便地在程序中创建文件描述符的副本,这在需要在不同的上下文中使用同一个文件,或者在需要临时改变文件描述符的属性(如设置非阻塞模式)时非常有用。

如何使用:当 cmd=F_DUPFD 时,它的作用会根据 fd 复制出一个新的文件描述符,此时需要传入第三个参数,第三个参数用于指出新复制出的文件描述符是一个大于或等于该参数的可用文件描述符(没有使用的文件描述符) ;如果第三个参数等于一个已经存在的文件描述符,则取一个大于该参数的可用文件描述符。测试示例如下:

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main() {
    int original_fd = open("myfile.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
    if (original_fd == -1) {
        perror("open");
        return 1;
    }

    // 指定新文件描述符的最小值为 10
    int new_fd = fcntl(original_fd, F_DUPFD, 10);
    if (new_fd == -1) {
        perror("fcntl");
        close(original_fd);
        return 1;
    }

    printf("Original file descriptor: %d\n", original_fd);
    printf("New file descriptor: %d\n", new_fd);

    // 关闭文件描述符
    close(original_fd);
    close(new_fd);
    return 0;
}

在这个示例中,我们首先打开一个名为 "myfile.txt" 的文件,获取其文件描述符 original_fd。接着,我们使用 fcntl() 函数和 F_DUPFD 命令来复制这个文件描述符,并指定新文件描述符的最小值为 10。如果成功,fcntl() 将返回新的文件描述符 new_fd,它与 original_fd 指向同一个文件。最后,我们打印出原始和新的文件描述符,并关闭它们。运行结果如下:

2.3 获取/设置文件状态标志(F_GETFL/F_SETFL )

cmd=F_GETFL 可用于获取文件状态标志, cmd=F_SETFL 可用于设置文件状态标志。

  • cmd=F_GETFL 时不需要传入第三个参数,返回值成功表示获取到的文件状态标志;
  • cmd=F_SETFL 时,需要传入第三个参数,此参数表示需要设置的文件状态标志。

这些标志指的就是我们在调用 open 函数时传入的 flags 标志, 可以指定一个或多个(通过位或 | 运算符组合), 但是文件权限标志(O_RDONLY、 O_WRONLY、 O_RDWR)以及文件创建标志(O_CREAT、O_EXCL、 O_NOCTTY、 O_TRUNC)不能被设置;只有 O_APPEND、 O_ASYNC、O_DIRECT、 O_NOATIME 以及 O_NONBLOCK 这些标志可以被修改。 所以对于一个已经打开的文件描述符,可以通过这种方式添加或移除标志。

下面的示例代码,如何、首先获取文件状态标志,然后修改它们,并将修改后的标志应用到文件描述符上:

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main() {
    // 打开文件
    int fd = open("myfile.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 获取当前文件状态标志
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1) {
        perror("fcntl F_GETFL");
        close(fd);
        return 1;
    }

    printf("Original file status flags: %o\n", flags);

    // 打印当前标志并设置为非阻塞模式
    printf("Setting O_NONBLOCK flag.\n");
    flags |= O_NONBLOCK;  // 添加非阻塞标志

    // 设置新的文件状态标志
    if (fcntl(fd, F_SETFL, flags) == -1) {
        perror("fcntl F_SETFL");
        close(fd);
        return 1;
    }

    // 再次获取文件状态标志以验证更改
    flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1) {
        perror("fcntl F_GETFL after F_SETFL");
        close(fd);
        return 1;
    }

    printf("New file status flags after setting O_NONBLOCK: %o\n", flags);

    // 关闭文件描述符
    close(fd);
    return 0;
}

程序中,首先使用 open() 函数打开一个文件,并获取其文件描述符 fd。然后,我们使用 fcntl() 函数和 F_GETFL 命令来获取文件的当前状态标志,并打印它们。

接着,通过逻辑或操作 flags |= O_NONBLOCK; 来设置 O_NONBLOCK 标志,这将文件描述符设置为非阻塞模式。之后,我们再次使用 fcntl() 函数和 F_SETFL 命令来应用这些更改。并再次获取并打印文件状态标志。

程序运行结果如下:


 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

绘画新手必备!六款免费易用的绘图软件推荐

在当今的数字世界里有各种各样的设计创作工具&#xff0c;那么问题来了我们应该如何在众多免费绘图软件中选择呢&#xff1f;为了回答这个问题&#xff0c;我们将在本文中介绍和测评六个领先的绘图软件。每一个都有自己独特的特点和优势&#xff0c;适合不同的需求和用户。以下…

Django缓存

由于Django是动态网站&#xff0c;所有每次请求均会去数据进行相应的操作&#xff0c;当程序访问量大时&#xff0c;耗时必然会更加明显&#xff0c;最简单解决方式是使用&#xff1a;缓存&#xff0c;缓存将一个某个views的返回值保存至内存或者memcache中&#xff0c;若某个时…

C++设计模式-策略模式,AI角色动态选择行为

运行在VS2022&#xff0c;x86&#xff0c;Debug下。 27. 策略模式 策略模式让算法的选择与使用独立开来&#xff0c;使得代码更灵活、可扩展和易维护。应用&#xff1a;如在游戏开发中&#xff0c;AI角色需要根据环境和条件做出不同的行为&#xff0c;如寻路、攻击、躲避等。可…

【优选算法】栈 {何时使用栈结构?后缀表达式求值;中缀转后缀表达式;中缀表达式求值}

一、经验总结 何时使用栈结构解题&#xff1f; 做过相似的使用栈结构解得的题目嵌套处理&#xff1a;在从前向后处理的过程中&#xff0c;由于之后内容的不确定性而导致当前操作不能贸然进行&#xff0c;需要先进行保存&#xff0c;直到遇到区间结束标志&#xff08;如’)&am…

2024年船舶、机械制造与海洋科学国际会议(ICSEMMS2024)

2024年船舶、机械制造与海洋科学国际会议&#xff08;ICSEMMS2024&#xff09; 会议简介 我们诚挚邀请您参加将在重庆隆重举行的2024年国际造船、机械制造和海洋科学大会&#xff08;ICSEMMS024&#xff09;。作为一项跨学科和跨学科的活动&#xff0c;本次会议旨在促进造船…

PostgreSQL专家(pcp51)--王丁丁

#PostgreSQL培训 #postgresql认证 #postgreSQL考试 #PG考试 #PG培训

【Python系列】Python装饰器

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【实战JVM】-实战篇-06-GC调优

文章目录 1 GC调优概述1.1 调优指标1.1.1 吞吐量1.1.2 延迟1.1.3 内存使用量 2 GC调优方法2.1 发现问题2.1.1 jstat工具2.1.2 visualvm插件2.1.3 PrometheusGrafana2.1.4 GC Viewer2.1.5 GCeasy 2.2 常见GC模式2.2.1 正常情况2.2.2 缓存对象过多2.2.3 内存泄漏2.2.4 持续FullGC…

【全开源】小区入户安检系统(FastAdmin + Uni-APP)

守护家的每一道防线 一款基于FastAdmin Uni-APP开发的小区入户安检系统(前端可发布为小程序、H5、App)。可针对不同行业自定义安检项目&#xff0c;线下安检&#xff0c;线上留存&#xff08;安检拍照/录像&#xff09;&#xff0c;提高安检人员安检效率。 一、引言&#xff…

NLP(1)-TF-IDF算法介绍

一、TF-IDF算法介绍 TF-IDF&#xff08;term frequency–inverse document frequency&#xff0c;词频-逆向文件频率&#xff09;是一种用于信息检索&#xff08;information retrieval&#xff09;与文本挖掘&#xff08;text mining&#xff09;的常用加权技术。 TF-IDF是一…

升级HarmonyOS 4.2,开启健康生活篇章

夏日来临&#xff0c;华为智能手表携 HarmonyOS 4.2 版本邀您体验&#xff0c;它不仅可以作为时尚单品搭配夏日绚丽服饰&#xff0c;还能充当你的健康管家&#xff0c;从而更了解自己的身体&#xff0c;开启智能健康生活篇章。 高血糖风险评估优化&#xff0c;健康监测更精准 …

Java面向对象笔记

多态 一种类型的变量可以引用多种实际类型的对象 如 package ooplearn;public class Test {public static void main(String[] args) {Animal[] animals new Animal[2];animals[0] new Dog();animals[1] new Cat();for (Animal animal : animals){animal.eat();}} }class …

html 使用svg矢量图时无法 调整宽高问题解决,不能像图片一样设置宽高比例问题

引入的路径后加 #svgView(preserveAspectRatio(none)) 具体代码如下 修改前 <img src"/assets/svgs/full_screen_full.svg" class"im"> 修改后 <img src"/assets/svgs/full_screen_full.svg#svgView(preserveAspectRatio(none))" cla…

前端处理流式数据(SSE服务)

前言 将数据用流的方式返回给客户端,这种技术需求在传统的管理项目中不多见,但是在媒体或者有实时消息等功能上就会用到,这个知识点对于前端还是很重要的。 即时你不写服务端,但是服务端如果给你这样的接口,你也得知道怎么去使用联调。 nodejs实现简单的SSE服务 SSE服务(Se…

Java:流程控制语句

文章目录 一、顺序结构二、分支结构2.1 if2.2 switch 三、循环结构3.1 for3.2 while3.3 do...while 四、流程控制4.1 break4.2 continue 五、结语 一、顺序结构 顺序结构语句是Java程序默认的执行流程&#xff0c;按照代码的先后顺序&#xff0c;从上到下依次执行。 二、分支结…

宏集Panorama SCADA:个性化定制,满足多元角色需求

前言 在考虑不同人员在企业中的职能和职责时&#xff0c;他们对于SCADA系统的需求可能因其角色和工作职责的不同而有所差异。在SCADA系统的设计和实施过程中&#xff0c;必须充分考虑和解决这种差异性。 为了满足不同人员的需求, 宏集Panorama SCADA平台具备灵活的功能和定制…

新书速览|Python Django 4构建动态网站的16堂课

Python Django 4构建动态网站的16堂课 本书内容 《Python Django 4构建动态网站的16堂课》是一本关于Django框架的网站开发入门教材&#xff0c;适合想要学习并掌握Django框架的开发人员阅读。《Python Django 4构建动态网站的16堂课》共分16课&#xff0c;内容包括网站开发环境…

影响指挥中心操作台的材质选择的因素有哪些

指挥中心操作台作为现代指挥系统的重要组成部分&#xff0c;其材质的选择不仅关系到操作台的使用寿命和稳定性&#xff0c;更直接影响到整个指挥中心的运行效率和安全性。因此&#xff0c;对指挥中心操作台的材质设定一系列标准显得尤为重要。 耐用性考量&#xff1a;鉴于指挥中…

Android Dialog使用汇总

Dialog分类 AlertDialog Dialog 类是对话框的基类&#xff0c;官方建议我们不要直接实例化它&#xff0c;而是使用其子类来获取实例。AlertDialog是系统提供的一个直接子类&#xff0c;它能帮助我们快速构建出不同类型的弹窗。接下来就看下各种类型弹窗的使用。 1、普通对话框…

【遗传算法】【机器学习】【Python】常见交叉方法(一)、单点交叉和两点交叉

一、遗传算法流程图 交叉过程即存在于上图的”交叉“&#xff08;crossover&#xff09;步骤中。 二、单点交叉 随机地选择1个交叉位点进行交叉&#xff0c;如下图所示&#xff1a; 用random库实现随机性&#xff1a; import random# 简单的单点交叉方式 def sing_muta(lis…